diff --git a/setup.py b/setup.py index 7a55d24..48f3994 100644 --- a/setup.py +++ b/setup.py @@ -5,6 +5,7 @@ import platform from setuptools import Extension, setup from Cython.Build import cythonize +#from _version import __version__ as vttpy_version here = os.path.abspath(os.path.dirname(__file__)) @@ -30,14 +31,15 @@ 'vttcompilepy.vttcompilepy', define_macros=define_macros, include_dirs=[".","src"], - sources=['vttcompilepy/vttcompilepy.pyx','src/application.cpp','src/CvtManager.cpp','src/File.cpp','src/List.cpp', 'src/MathUtils.cpp', 'src/Memory.cpp','src/Platform.cpp','src/TextBuffer.cpp', 'src/TMTParser.cpp', 'src/TTAssembler.cpp', 'src/TTEngine.cpp', 'src/TTFont.cpp', 'src/TTGenerator.cpp', 'src/Variation.cpp', 'src/VariationInstance.cpp', 'src/VariationModels.cpp' ], + sources=['vttcompilepy/vttcompilepy.pyx','src/application.cpp','src/CvtManager.cpp','src/File.cpp','src/List.cpp', 'src/MathUtils.cpp', 'src/Memory.cpp','src/Platform.cpp','src/TextBuffer.cpp', 'src/TMTParser.cpp', 'src/TTAssembler.cpp', 'src/TTEngine.cpp', 'src/TTFont.cpp', 'src/TTGenerator.cpp', 'src/Variation.cpp', 'src/VariationInstance.cpp', 'src/VariationModels.cpp', 'src/ttiua.cpp' ], language='c++', extra_compile_args=extra_compile_args, ) setup( name="vttcompilepy", - version= '0.0.1.5', + #version= vttpy_version, + version= '0.0.1.6', description="Python extension for Visual TrueType font compile. ", long_description=long_description, long_description_content_type='text/markdown', @@ -52,6 +54,9 @@ package_dir={"": "."}, packages=["vttcompilepy"], zip_safe=False, + install_requires=[ + "fonttools>=4.33.0", + ], python_requires=">=3.7", ext_modules = cythonize( extension, diff --git a/src/TTAssembler.cpp b/src/TTAssembler.cpp index 29eb358..19bd603 100644 --- a/src/TTAssembler.cpp +++ b/src/TTAssembler.cpp @@ -141,6 +141,8 @@ typedef struct { #define tt_WildCardInPush 76 #define tt_JumpNegativeForByte 77 +#define tt_ExpectingAValue 78 + #define tt_NotImplemented 9999 #define tt_Push_Switch 1 #define tt_PushOn_Switch 2 @@ -149,6 +151,7 @@ typedef struct { #define tt_End_Switch 5 #define tt_GHTBlockBegin_Switch 6 #define tt_GHTBlockEnd_Switch 7 +#define tt_MaxStack_Switch 8 #define co_NoError 0 @@ -187,7 +190,8 @@ typedef struct { short LastCommandWasAnEND; /* to check if the ENDF, ELSE or EIF is preceeded by #END (end of block) */ short ELSEStatus[MAXIFRECURSION]; /* to keep track in embedded IF statement if we are already in the ELSE clause */ -} tt_CompilationStatus; + short ExplicitMaxStack; + } tt_CompilationStatus; void TT_memSwap( char *a,char *b,char *tmp,int32_t len ); @@ -261,7 +265,8 @@ tt_CompilerSwitchType tt_CompilerSwitch[] = { { L"END", L"End of a block", tt_End_Switch }, { L"GHTBLOCK", L"Beginning of a new Sampo block", tt_GHTBlockBegin_Switch }, { L"GHTB", L"Beginning of a new Sampo block", tt_GHTBlockBegin_Switch }, - { L"GHTE", L"End of a new Sampo block", tt_GHTBlockEnd_Switch } + { L"GHTE", L"End of a new Sampo block", tt_GHTBlockEnd_Switch }, + {L"MAXSTACK", L"Max Stack", tt_MaxStack_Switch } }; #define asm_SLOOP 0x17 @@ -1381,6 +1386,12 @@ short TT_IsDelta( unsigned short opCode ) short TT_IsPushBW( unsigned short opCode ); short TT_IsPushBW( unsigned short opCode ) +{ + return (opCode >= 0xB0 && opCode <= 0xBF); +} + +short TT_Is_PushBW_or_NPushBW(unsigned short opCode); +short TT_Is_PushBW_or_NPushBW(unsigned short opCode) // register unsigned char opCode; { return ( ( opCode >= 0xB0 && opCode <= 0xBF) || opCode == 0x40 || opCode == 0x41 ); @@ -1657,7 +1668,7 @@ wchar_t * TT_ReadInstructionParameters (wchar_t * CurrentPtr, wchar_t * EOLPtr, flashingPoints->NumberOfFlashingPoint = 0; } - if (pushOn || TT_IsPushBW(InstructionCode)) + if (pushOn || TT_Is_PushBW_or_NPushBW(InstructionCode)) { argNb = (short)STRLENW(ArgTypeBuffer); @@ -1666,7 +1677,7 @@ wchar_t * TT_ReadInstructionParameters (wchar_t * CurrentPtr, wchar_t * EOLPtr, argNb = 255; }; - if (TT_IsPushBW(InstructionCode)) + if (TT_Is_PushBW_or_NPushBW(InstructionCode)) { if (TT_IsNPushBW(InstructionCode)) { @@ -1721,7 +1732,7 @@ wchar_t * TT_ReadInstructionParameters (wchar_t * CurrentPtr, wchar_t * EOLPtr, if ( *CurrentPtr == L'*' ) { - if (TT_IsPushBW(InstructionCode)) + if (TT_Is_PushBW_or_NPushBW(InstructionCode)) { *tt_error = tt_WildCardInPush; return (CurrentPtr); @@ -1761,6 +1772,14 @@ wchar_t * TT_ReadInstructionParameters (wchar_t * CurrentPtr, wchar_t * EOLPtr, /* function definition, we need to update MaxFunctionDefs */ if (args[argindex] > *MaxFunctionDefs) *MaxFunctionDefs = args[argindex] ; *argc = *argc + 1; + + } else if ((argNb != 255) && TT_IsPushBW(InstructionCode)) + { + CurrentPtr = TT_ParseNumber(CurrentPtr, EOLPtr, &args[argindex], SelectionLength, tt_error); + if (*tt_error != tt_NoError) + return CurrentPtr; + + *argc = *argc + 1; } else { short foundPP, PPindex; @@ -1882,104 +1901,105 @@ wchar_t * TT_ReadInstructionParameters (wchar_t * CurrentPtr, wchar_t * EOLPtr, while ( *CurrentPtr == L' ' && CurrentPtr <= EOLPtr) CurrentPtr++; - if ( *CurrentPtr++ != L',' || CurrentPtr >= EOLPtr ) + // process parameters to the jump if present + if (!(CurrentPtr >= EOLPtr) && (*CurrentPtr == L',')) { - *tt_error = tt_EmptyParameterList; - return (CurrentPtr-1); - } - - /* skip extra spaces */ - while ( *CurrentPtr == L' ' && CurrentPtr <= EOLPtr) - CurrentPtr++; + if (*CurrentPtr++ != L',' || CurrentPtr >= EOLPtr) + { + *tt_error = tt_EmptyParameterList; + return (CurrentPtr - 1); + } - if ( *CurrentPtr++ != L'(' || (CurrentPtr >= EOLPtr) ) - { - *tt_error = tt_JRExpectingABracket; - return (CurrentPtr-1); - } + /* skip extra spaces */ + while (*CurrentPtr == L' ' && CurrentPtr <= EOLPtr) + CurrentPtr++; - /* skip extra spaces */ - while ( *CurrentPtr == L' ' && CurrentPtr <= EOLPtr) - CurrentPtr++; + if (*CurrentPtr++ != L'(' || (CurrentPtr >= EOLPtr)) + { + *tt_error = tt_JRExpectingABracket; + return (CurrentPtr - 1); + } - /* parse the Bn or Wn label */ - if ( (*CurrentPtr != L'B' && *CurrentPtr != L'W') || (CurrentPtr >= EOLPtr) ) - { - *tt_error = tt_JRExpectingABWLabel; - return (CurrentPtr); - } - - StringLength = TT_GetStringLength (CurrentPtr, EOLPtr); - if (StringLength < 2) - { - *tt_error = tt_VoidLabel; - return (CurrentPtr); - } - - if (StringLength >= MAXLABELLENGTH) - { - *tt_error = tt_LabelTooLong; - return (CurrentPtr); - } + /* skip extra spaces */ + while (*CurrentPtr == L' ' && CurrentPtr <= EOLPtr) + CurrentPtr++; + /* parse the Bn or Wn label */ + if ((*CurrentPtr != L'B' && *CurrentPtr != L'W') || (CurrentPtr >= EOLPtr)) + { + *tt_error = tt_JRExpectingABWLabel; + return (CurrentPtr); + } - *BWLabelLength = (short)StringLength; - *BWLabelHandle = CurrentPtr; + StringLength = TT_GetStringLength(CurrentPtr, EOLPtr); + if (StringLength < 2) + { + *tt_error = tt_VoidLabel; + return (CurrentPtr); + } - CurrentPtr = CurrentPtr + StringLength; + if (StringLength >= MAXLABELLENGTH) + { + *tt_error = tt_LabelTooLong; + return (CurrentPtr); + } - /* skip extra spaces */ - while ( *CurrentPtr == L' ' && CurrentPtr <= EOLPtr) - CurrentPtr++; + *BWLabelLength = (short)StringLength; + *BWLabelHandle = CurrentPtr; - if ( *CurrentPtr++ != L'=' || (CurrentPtr >= EOLPtr) ) - { - *tt_error = tt_JRExpectingAEqual; - return (CurrentPtr-1); - } + CurrentPtr = CurrentPtr + StringLength; - /* skip extra spaces */ - while ( *CurrentPtr == L' ' && CurrentPtr <= EOLPtr) - CurrentPtr++; + /* skip extra spaces */ + while (*CurrentPtr == L' ' && CurrentPtr <= EOLPtr) + CurrentPtr++; - if ( *CurrentPtr++ != L'#' || (CurrentPtr >= EOLPtr) ) - { - *tt_error = tt_JRExpectingALabel; - return (CurrentPtr-1); - } + if (*CurrentPtr++ != L'=' || (CurrentPtr >= EOLPtr)) + { + *tt_error = tt_JRExpectingAEqual; + return (CurrentPtr - 1); + } + /* skip extra spaces */ + while (*CurrentPtr == L' ' && CurrentPtr <= EOLPtr) + CurrentPtr++; - StringLength = TT_GetStringLength (CurrentPtr, EOLPtr); - if (StringLength >= MAXLABELLENGTH) - { - *tt_error = tt_LabelTooLong; - *SelectionLength = StringLength; - return (CurrentPtr); - } + if (*CurrentPtr++ != L'#' || (CurrentPtr >= EOLPtr)) + { + *tt_error = tt_JRExpectingALabel; + return (CurrentPtr - 1); + } - if ( StringLength == 0 ) - { - *tt_error = tt_VoidLabel; - *SelectionLength = StringLength; - return (CurrentPtr); - } + StringLength = TT_GetStringLength(CurrentPtr, EOLPtr); + if (StringLength >= MAXLABELLENGTH) + { + *tt_error = tt_LabelTooLong; + *SelectionLength = StringLength; + return (CurrentPtr); + } - *LabelLength = (short)StringLength; - *LabelHandle = CurrentPtr; + if (StringLength == 0) + { + *tt_error = tt_VoidLabel; + *SelectionLength = StringLength; + return (CurrentPtr); + } - CurrentPtr = CurrentPtr + StringLength; + *LabelLength = (short)StringLength; + *LabelHandle = CurrentPtr; - /* skip extra spaces */ - while ( *CurrentPtr == L' ' && CurrentPtr <= EOLPtr) - CurrentPtr++; + CurrentPtr = CurrentPtr + StringLength; - if ( *CurrentPtr != L')' || (CurrentPtr >= EOLPtr) ) - { - *tt_error = tt_JRExpectingABracket; - return (CurrentPtr-1); - } - CurrentPtr++; + /* skip extra spaces */ + while (*CurrentPtr == L' ' && CurrentPtr <= EOLPtr) + CurrentPtr++; + if (*CurrentPtr != L')' || (CurrentPtr >= EOLPtr)) + { + *tt_error = tt_JRExpectingABracket; + return (CurrentPtr - 1); + } + CurrentPtr++; + } } return CurrentPtr; } @@ -1998,7 +2018,7 @@ void TT_StoreArgumentsAndInstruction (unsigned char InstructionCode, short ** aH **iHandle = InstructionCode; *iHandle = *iHandle +1; - if (TT_IsPushBW(InstructionCode)) + if (TT_Is_PushBW_or_NPushBW(InstructionCode)) { /* PUSH arguments goes to the instruction stream */ short index = 0; @@ -2833,6 +2853,44 @@ wchar_t *TT_InnerCompile( CompilationStatus->WeAreInsideGHBlock = false; CurrentPtr = CurrentPtr + LineLength; break; + case tt_MaxStack_Switch: + if (CompilationStatus->WeAreInsideGHBlock) + { + CurrentPtr = CurrentPtr + LineLength; + } + else + { + wchar_t* EOLPtr; + EOLPtr = CurrentPtr + LineLength; + short maxStack = 0; + + CurrentPtr = CurrentPtr + StringLength + 1; + + /* skip spaces */ + while (*CurrentPtr == L' ' && CurrentPtr <= EOLPtr) + CurrentPtr++; + + if (CurrentPtr >= EOLPtr) + *tt_error = tt_ExpectingAValue; + + /* look for the comma */ + if (*CurrentPtr != L',') + { + break; /* it could be a comment */ + } + CurrentPtr = CurrentPtr + 1; + + /* skip extra spaces */ + while (*CurrentPtr == L' ' && CurrentPtr <= EOLPtr) + CurrentPtr++; + + if (CurrentPtr >= EOLPtr) + *tt_error = tt_ExpectingAValue; + + CurrentPtr = TT_ParseNumber(CurrentPtr, EOLPtr, &maxStack, SelectionLength, tt_error); + CompilationStatus->ExplicitMaxStack = maxStack; + } + break; } } } @@ -2932,7 +2990,7 @@ wchar_t *TT_InnerCompile( EOLPtr = CurrentPtr + LineLength; CurrentPtr = TT_ReadInstructionBooleans (CurrentPtr+StringLength, EOLPtr, InstructionIndex, &InstructionCode, SelectionLength, tt_error); - if (TT_IsPushBW(InstructionCode) && CompilationStatus->WeAreInPushOnMode && *tt_error == tt_NoError) + if (TT_Is_PushBW_or_NPushBW(InstructionCode) && CompilationStatus->WeAreInPushOnMode && *tt_error == tt_NoError) { *tt_error = tt_PUSHBWInPushON; *SelectionLength = LineLength; @@ -3015,7 +3073,7 @@ wchar_t *TT_InnerCompile( *BinaryOffset = (short)(ptrdiff_t)(iPtr - insStore); } - if (TT_IsPushBW(InstructionCode)) + if (TT_Is_PushBW_or_NPushBW(InstructionCode)) { if (iPtr + 1 + 2 * argc > InnerBinaryOutMaxPtr) { @@ -3036,6 +3094,12 @@ wchar_t *TT_InnerCompile( } } + if (TT_Is_PushBW_or_NPushBW(InstructionCode)) + { + //numberofArgs = (short)(ptrdiff_t)(aPtr - argStore); /* number of arguments */ + *StackNeed = *StackNeed + argc; + } + TT_StoreArgumentsAndInstruction((unsigned char)InstructionCode, &aPtr, &iPtr, argc, args, argc2, args2, tt_error); } } @@ -3102,7 +3166,7 @@ wchar_t *TT_Compile( /* line number where the first error occur */ short * ErrorLineNb, /* return : approximate stack need, higher function number */ - short * StackNeed, short * MaxFunctionDefs, + short* StackNeed, short* MaxFunctionDefs, short* ExplicitStackNeed, /* for the DovMan partial compilation feature that flash points referenced by the current command */ tt_flashingPoints * flashingPoints, @@ -3113,11 +3177,13 @@ wchar_t *TT_Compile( wchar_t *TT_Compile(wchar_t *StartPtr, wchar_t * EndPtr, wchar_t * SelStartPtr, unsigned char * BinaryOut, int32_t MaxBinaryLength, int32_t * BinaryLength, short * BinaryOffset, int32_t * SelectionLength, short * ErrorLineNb, - short * StackNeed, short * MaxFunctionDefs, + short* StackNeed, short* MaxFunctionDefs, short* ExplicitStackNeed, /* for the DovMan partial compilation feature that flash points referenced by the current command */ tt_flashingPoints * flashingPoints, ASMType asmType, short * tt_error) { + assert(ExplicitStackNeed != nullptr); + tt_CompilationStatus CompilationStatus; wchar_t * Result; char * BinaryOutEndPtr; @@ -3138,6 +3204,7 @@ wchar_t *TT_Compile(wchar_t *StartPtr, wchar_t * EndPtr, wchar_t * SelStartPtr, CompilationStatus.LastCommandWasAnIDEF = false; CompilationStatus.LastCommandWasAnJUMP = false; CompilationStatus.LastCommandWasAnEND = false; + CompilationStatus.ExplicitMaxStack = 0; flashingPoints->NumberOfFlashingPoint = 0; @@ -3159,6 +3226,11 @@ wchar_t *TT_Compile(wchar_t *StartPtr, wchar_t * EndPtr, wchar_t * SelStartPtr, { *tt_error = tt_IDEFwithoutENDF; } + + if (*tt_error == tt_NoError) + { + *ExplicitStackNeed = CompilationStatus.ExplicitMaxStack; + } return Result; } @@ -3402,6 +3474,9 @@ void TT_GetErrorString (short ErrorNb, wchar_t * ErrorString, size_t errorString case tt_WildCardInPush: swprintf(ErrorString, errorStringLen, L"Invalid use * in a PUSH instruction"); break; + case tt_ExpectingAValue: + swprintf(ErrorString, errorStringLen, L"Expecting a value"); + break; case tt_NotImplemented: swprintf(ErrorString, errorStringLen, L"Not implemented"); @@ -4003,7 +4078,7 @@ bool TTAssemble(ASMType asmType, TextBuffer* src, TrueTypeFont* font, TrueTypeGl int32_t maxBinLen, unsigned char* bin, int32_t* actBinLen, bool variationCompositeGuard, int32_t* errPos, int32_t* errLen, wchar_t errMsg[], size_t errMsgLen) { wchar_t* startPtr, * endPtr, * SelStartPtr, * tempPtr; - short BinaryOffset, CompileError = co_NoError, StackNeed, MaxFunctionDefs, ErrorLineNb, componentSize, numCompositeContours, numCompositePoints, maxContourNumber, maxPointNumber; + short BinaryOffset, CompileError = co_NoError, StackNeed, MaxFunctionDefs, ExplicitStackNeed, ErrorLineNb, componentSize, numCompositeContours, numCompositePoints, maxContourNumber, maxPointNumber; int32_t srcLen, highestCvtNum; sfnt_maxProfileTable profile; short componentData[MAXCOMPONENTSIZE]; @@ -4085,12 +4160,13 @@ bool TTAssemble(ASMType asmType, TextBuffer* src, TrueTypeFont* font, TrueTypeGl StackNeed = 0; MaxFunctionDefs = 0; + ExplicitStackNeed = 0; tempPtr = TT_Compile(tempPtr, endPtr, SelStartPtr, bin, maxBinLen, actBinLen, - &BinaryOffset, errLen, &ErrorLineNb, &StackNeed, &MaxFunctionDefs, &MyflashingPoints, asmType, &CompileError); + &BinaryOffset, errLen, &ErrorLineNb, &StackNeed, &MaxFunctionDefs, &ExplicitStackNeed, &MyflashingPoints, asmType, &CompileError); if (CompileError == tt_NoError) { - font->UpdateAssemblerProfile(asmType, MaxFunctionDefs + 1, StackNeed, (short)(*actBinLen)); + font->UpdateAssemblerProfile(asmType, MaxFunctionDefs + 1, StackNeed, ExplicitStackNeed, (short)(*actBinLen)); } else { *errPos = (int32_t)(tempPtr - startPtr); diff --git a/src/TTFont.cpp b/src/TTFont.cpp index 76660d2..6505f71 100644 --- a/src/TTFont.cpp +++ b/src/TTFont.cpp @@ -263,6 +263,7 @@ bool TrueTypeFont::Create() { this->cvarBinSize = 0; this->horMetric = (sfnt_HorizontalMetrics *)NewP(sizeof(sfnt_HorizontalMetrics)*this->maxGlitEntries); this->gaspLoaded = false; + this->explicitMaxStackElements = 0; return this->sfntHandle && this->sfntTmpHandle && this->offsetTable && this->tmpOffsetTable && this->cvt && this->IndexToLoc && this->tmpIndexToLoc && this->glit1 && this->glit2 && this->charCodeOf && this->charGroupOf && this->horMetric && this->glyphIndexMap; @@ -547,9 +548,24 @@ bool TrueTypeFont::IsMakeTupleName(const std::wstring &name) const return false; } // TrueTypeFont::IsMakeTupleName -bool TrueTypeFont::Read(File *file, TrueTypeGlyph *glyph, short *platformID, short *encodingID, wchar_t errMsg[], size_t errMsgLen) { - int32_t glyphIndex; +bool TrueTypeFont::Read(void* font, uint32_t fontLen, TrueTypeGlyph* glyph, short* platformID, short* encodingID, wchar_t errMsg[], size_t errMsgLen) +{ + this->sfntSize = fontLen; + + this->AssertMaxSfntSize(this->sfntSize, true, true); + + if (this->sfntSize > this->maxSfntSize) + { + MaxSfntSizeError(L"Read: This font is too large", this->sfntSize, errMsg, errMsgLen); return false; + } + + memcpy(this->sfntHandle, font, this->sfntSize); + return this->Read(glyph, platformID, encodingID, errMsg, errMsgLen); +} + +bool TrueTypeFont::Read(File *file, TrueTypeGlyph *glyph, short *platformID, short *encodingID, wchar_t errMsg[], size_t errMsgLen) { + this->sfntSize = file->Length(); this->AssertMaxSfntSize(this->sfntSize,true,true); @@ -561,48 +577,76 @@ bool TrueTypeFont::Read(File *file, TrueTypeGlyph *glyph, short *platformID, sho if (file->Error()) { swprintf(errMsg, errMsgLen, L"Read: I/O error reading this font"); return false; } - - if (!this->UnpackHeadHheaMaxpHmtx(errMsg, errMsgLen)) return false; - if(*platformID == 3 && *encodingID == 1) + return this->Read(glyph, platformID, encodingID, errMsg, errMsgLen); +} // TrueTypeFont::Read + +bool TrueTypeFont::Read(TrueTypeGlyph* glyph, short* platformID, short* encodingID, wchar_t errMsg[], size_t errMsgLen){ + int32_t glyphIndex = 0; + + if (!this->UnpackHeadHheaMaxpHmtx(errMsg, errMsgLen)) + return false; + + if (*platformID == 3 && *encodingID == 1) *encodingID = 10; // lets first try 3,10 and default lower if not present - - if (!this->CMapExists(*platformID,*encodingID) && !this->DefaultCMap(platformID,encodingID,errMsg, errMsgLen)) return false; - + + if (!this->CMapExists(*platformID, *encodingID) && !this->DefaultCMap(platformID, encodingID, errMsg, errMsgLen)) + return false; + if (!(this->UnpackGlitsLoca(errMsg, errMsgLen) && this->UpdateMaxPointsAndContours(errMsg, errMsgLen) && this->UnpackCMap(*platformID, *encodingID, errMsg, errMsgLen) && this->UnpackCharGroup(errMsg, errMsgLen))) return false; - - // Clear for new font. + + // Clear for new font. if (instanceManager_ != nullptr) { - instanceManager_->clear(); + instanceManager_->clear(); } if (!this->SetSfnt(*platformID, *encodingID, errMsg, errMsgLen)) return false; // not the smartest way to get these numbers, another historical legacy - if ((glyphIndex = this->GlyphIndexOf(L'H')) == INVALID_GLYPH_INDEX) this->capHeight = this->unitsPerEm; + if ((glyphIndex = this->GlyphIndexOf(L'H')) == INVALID_GLYPH_INDEX) + this->capHeight = this->unitsPerEm; else if (this->GetGlyph(glyphIndex, glyph, errMsg, errMsgLen)) this->capHeight = glyph->ymax; - else return false; - if ((glyphIndex = this->GlyphIndexOf(L'x')) == INVALID_GLYPH_INDEX) this->xHeight = this->unitsPerEm; + else + return false; + if ((glyphIndex = this->GlyphIndexOf(L'x')) == INVALID_GLYPH_INDEX) + this->xHeight = this->unitsPerEm; else if (this->GetGlyph(glyphIndex, glyph, errMsg, errMsgLen)) this->xHeight = glyph->ymax; - else return false; - if ((glyphIndex = this->GlyphIndexOf(L'p')) == INVALID_GLYPH_INDEX) this->descenderHeight = 0; + else + return false; + if ((glyphIndex = this->GlyphIndexOf(L'p')) == INVALID_GLYPH_INDEX) + this->descenderHeight = 0; else if (this->GetGlyph(glyphIndex, glyph, errMsg, errMsgLen)) this->descenderHeight = glyph->ymin; - else return false; + else + return false; // Clear for new font. - if (this->postScriptNames) { + if (this->postScriptNames) + { delete this->postScriptNames; this->postScriptNames = NULL; } - + return true; // by now -} // TrueTypeFont::Read +} + +bool TrueTypeFont::Write(void* font, uint32_t fontLen, wchar_t errMsg[], size_t errMsgLen) +{ + if (this->sfntSize > fontLen) + { + swprintf(errMsg, errMsgLen, L"Not enough memory"); + return false; + } + + memcpy(font, this->sfntHandle, this->sfntSize); + + return true; +} bool TrueTypeFont::Write(File *file, wchar_t errMsg[], size_t errMsgLen) { file->WriteBytes(this->sfntSize, this->sfntHandle); @@ -656,6 +700,28 @@ int32_t TrueTypeFont::PrepBinSize(void) { return this->binSize[asmPREP]; } // TrueTypeFont::PrepBinSize +bool TrueTypeFont::GetPrepFromBin(TextBuffer* prepText, wchar_t errMsg[], size_t errMsgLen) +{ + unsigned char* data; + int32_t size; + + errMsg[0] = L'\0'; + data = this->GetTablePointer(tag_PreProgram); + size = this->GetTableLength(tag_PreProgram); + if (size > MAXBINSIZE) + { + swprintf(errMsg, errMsgLen, L"GetPrep: pre-program is %li bytes long (cannot be longer than %li bytes)", size, MAXBINSIZE); + return false; + } + + if (!this->UpdateBinData(asmPREP, size, data)) // !!! may not be necessary? + return false; + + TTIUnAsm(data, (unsigned short)size, prepText, true, false); + + return true; +} + bool TrueTypeFont::GetFpgm(TextBuffer *fpgmText, wchar_t errMsg[], size_t errMsgLen) { unsigned char *data; int32_t size; @@ -674,11 +740,64 @@ int32_t TrueTypeFont::FpgmBinSize(void) { return this->binSize[asmFPGM]; } // TrueTypeFont::FpgmBinSize +bool TrueTypeFont::GetFpgmFromBin(TextBuffer* fpgmText, wchar_t errMsg[], size_t errMsgLen) +{ + unsigned char* data; + int32_t size; + wchar_t buffer[maxLineSize]; + + errMsg[0] = L'\0'; + data = this->GetTablePointer(tag_FontProgram); + size = this->GetTableLength(tag_FontProgram); + if (size > MAXBINSIZE) + { + swprintf(errMsg, errMsgLen, L"GetFpgm: font program is %li bytes long (cannot be longer than %li bytes)", size, MAXBINSIZE); + return false; + } + + if (!this->UpdateBinData(asmFPGM, size, data)) // !!! may not be necessary? + return false; + + fpgmText->SetText(0, L""); + swprintf(buffer, errMsgLen, L"#MAXSTACK, %i" BRK, this->profile.maxStackElements); + fpgmText->Append(buffer); + + TTIUnAsm(data, (unsigned short)size, fpgmText, false, false); + + return true; +} + bool TrueTypeFont::GetGlyf(int32_t glyphIndex, TextBuffer *glyfText, wchar_t errMsg[], size_t errMsgLen) { return this->GetSource(true, glyphIndex, glyfText, errMsg, errMsgLen); // here we don't get any binary, this is done in GetGlyph, which also deals with the glyph's bounding box or composite information } // TrueTypeFont::GetGlyf +bool TrueTypeFont::GetGlyfFromBin(int32_t glyphIndex, TextBuffer* talkText, TextBuffer* glyfText, TrueTypeGlyph* glyph, wchar_t errMsg[], size_t errMsgLen) +{ + bool result; + wchar_t dateTime[32], buf[128]; + + DateTimeStrg(dateTime); + swprintf(buf, errMsgLen, L"/* TT glyph %li */" BRK L"/* Imported from binary" WIDE_STR_FORMAT "*/" BRK, glyphIndex, dateTime); + + result = this->GetGlyph(glyphIndex, glyph, errMsg, errMsgLen); + if (result) + { + if (glyph->composite) + { + glyfText->SetText((long)wcslen(buf), (wchar_t*)buf); + DisassemComponent(glyph, glyfText, errMsg, errMsgLen); + TTIUnAsm(this->binData[asmGLYF], (unsigned short)this->binSize[asmGLYF], glyfText, false, false); + } + else + { + talkText->SetText((long)wcslen(buf), (wchar_t*)buf); + TTIUnAsm(this->binData[asmGLYF], (unsigned short)this->binSize[asmGLYF], talkText, false, true); + } + } + + return result; +} bool TrueTypeFont::GetTalk(int32_t glyphIndex, TextBuffer *talkText, wchar_t errMsg[], size_t errMsgLen) { return this->GetSource(false, glyphIndex, talkText, errMsg, errMsgLen); @@ -3950,13 +4069,25 @@ void TrueTypeFont::UpdateMetricProfile(TrueTypeGlyph *glyph) { this->newMetricProfile.xMaxExtent = Max(this->newMetricProfile.xMaxExtent, glyph->xmax); } // TrueTypeFont::UpdateMetricProfile -void TrueTypeFont::UpdateAssemblerProfile(ASMType asmType, short maxFunctionDefs, short maxStackElements, short maxSizeOfInstructions) { +void TrueTypeFont::UpdateAssemblerProfile(ASMType asmType, short maxFunctionDefs, short maxStackElements, short explicitMaxStackElements, short maxSizeOfInstructions){ uint16 maxStackElementsPrepFpgm,maxStackElementsGlyfFpgm; this->profile.maxFunctionDefs = Max(this->profile.maxFunctionDefs,maxFunctionDefs); this->newProfile.maxFunctionDefs = Max(this->newProfile.maxFunctionDefs,maxFunctionDefs); - this->profile.maxStackElements = Max(this->profile.maxStackElements,maxStackElements); // <--- relevant during individual assembly + if (asmType == ASMType::asmFPGM) + { + this->explicitMaxStackElements = explicitMaxStackElements; + } + + if (this->explicitMaxStackElements) + { + this->profile.maxStackElements = this->explicitMaxStackElements; // <--- relevant during individual assembly + } + else + { + this->profile.maxStackElements = Max(this->profile.maxStackElements, maxStackElements); // <--- relevant during individual assembly + } // Coming up with a good max value for the number of stack elements used at any one time // is a bit of a heuristic, because we cannot possibly test all glyphs against all sizes @@ -4002,6 +4133,12 @@ void TrueTypeFont::UpdateAssemblerProfile(ASMType asmType, short maxFunctionDefs // the max stack depth then becomes the maximum of the two intermediate maxima above this->newProfile.maxStackElements = Max(maxStackElementsPrepFpgm,maxStackElementsGlyfFpgm); // <--- relevant during complete assembly/re-calc maxp + if (this->explicitMaxStackElements) { + this->newProfile.maxStackElements = this->explicitMaxStackElements; // <--- relevant during complete assembly/re-calc maxp + } else { + this->newProfile.maxStackElements = Max(maxStackElementsPrepFpgm, maxStackElementsGlyfFpgm); // <--- relevant during complete assembly/re-calc maxp + } + this->profile.maxSizeOfInstructions = Max(this->profile.maxSizeOfInstructions,maxSizeOfInstructions); this->newProfile.maxSizeOfInstructions = Max(this->newProfile.maxSizeOfInstructions,maxSizeOfInstructions); } // TrueTypeFont::UpdateAssemblerProfile diff --git a/src/TTFont.h b/src/TTFont.h index 436cf56..85418f5 100644 --- a/src/TTFont.h +++ b/src/TTFont.h @@ -319,15 +319,20 @@ class TrueTypeFont { virtual ~TrueTypeFont(void); void AssertMaxSfntSize(uint32_t minSfntSize, bool assertMainHandle, bool assertTempHandle); void AssertMaxGlyphs(int32_t minGlyphs); + bool Read(void* font, uint32_t fontLen, TrueTypeGlyph* glyph, short* platformID, short* encodingID, wchar_t errMsg[], size_t errMsgLen); bool Read(File *file, TrueTypeGlyph *glyph, short *platformID, short *encodingID, wchar_t errMsg[], size_t errMsgLen); + bool Write(void* font, uint32_t fontLen, wchar_t errMsg[], size_t errMsgLen); bool Write(File *file, wchar_t errMsg[], size_t errMsgLen); ControlValueTable *TheCvt(void); bool GetCvt (TextBuffer *cvtText, wchar_t errMsg[], size_t errMsgLen); bool GetPrep(TextBuffer *prepText, wchar_t errMsg[], size_t errMsgLen); + bool GetPrepFromBin(TextBuffer* prepText, wchar_t errMsg[], size_t errMsgLen); int32_t PrepBinSize(void); bool GetFpgm(TextBuffer *fpgmText, wchar_t errMsg[], size_t errMsgLen); + bool GetFpgmFromBin(TextBuffer* fpgmText, wchar_t errMsg[], size_t errMsgLen); int32_t FpgmBinSize(void); bool GetGlyf(int32_t glyphIndex, TextBuffer *glyfText, wchar_t errMsg[], size_t errMsgLen); + bool GetGlyfFromBin(int32_t glyphIndex, TextBuffer* talkText, TextBuffer* glyfText, TrueTypeGlyph* glyph, wchar_t errMsg[], size_t errMsgLen); bool GetTalk(int32_t glyphIndex, TextBuffer *talkText, wchar_t errMsg[], size_t errMsgLen); bool GetGlyph(int32_t glyphIndex, TrueTypeGlyph *glyph, wchar_t errMsg[], size_t errMsgLen); int32_t GlyfBinSize(void); @@ -369,7 +374,7 @@ class TrueTypeFont { void UseNewProfiles(void); sfnt_maxProfileTable GetProfile(void); void UpdateGlyphProfile(TrueTypeGlyph *glyph); // used not only in BuildNewSfnt, but also in calculation of maxp and other odd places... - void UpdateAssemblerProfile(ASMType asmType, short maxFunctionDefs, short maxStackElements, short maxSizeOfInstructions); + void UpdateAssemblerProfile(ASMType asmType, short maxFunctionDefs, short maxStackElements, short explicitMaxStackElements, short maxSizeOfInstructions); void UpdateCompositeProfile(TrueTypeGlyph *glyph, TTCompositeProfile *compositeProfile, short context, short RoundingCode, short InstructionIndex, short *args, short argc, sfnt_glyphbbox *Newbbox, short *error); bool GetNumberOfPointsAndContours(int32_t glyphIndex, short *contours, short *points, short *ComponentDepth, sfnt_glyphbbox *bbox); int32_t GetUnitsPerEm(void); // FUnits Per EM (2048 is typical) @@ -436,8 +441,14 @@ class TrueTypeFont { { return variationAxisTags_; } + + uint32_t Size() + { + return this->sfntSize; + } private: + bool Read(TrueTypeGlyph* glyph, short* platformID, short* encodingID, wchar_t errMsg[], size_t errMsgLen); void UpdateMetricProfile(TrueTypeGlyph *glyph); bool SubGetNumberOfPointsAndContours(int32_t glyphIndex, short *contours, short *points, short *ComponentDepth, sfnt_glyphbbox *bbox); bool TableExists(sfnt_TableTag tag); @@ -500,6 +511,7 @@ class TrueTypeFont { // 'maxp' (maximum profile) table sfnt_maxProfileTable profile; sfnt_maxProfileTable newProfile; // used for 'maxp' computation + uint16 explicitMaxStackElements; uint16 maxStackElements[numTTASMTypes]; // used for new heuristic in computing newProfile.maxStackElements // 'loca' (index to location) table @@ -585,4 +597,4 @@ enum class CheckCompositeResult {Success, Tolerance, Fail}; CheckCompositeResult CheckCompositeVariationCompatible(const short* pFirst, short firstSize, const short* pSecond, short secondSize); -#endif // TTFont_dot_h \ No newline at end of file +#endif // TTFont_dot_h diff --git a/src/application.cpp b/src/application.cpp index 51e9c47..9d89620 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -79,9 +79,14 @@ bool Application::OpenFont(std::string fileName, wchar_t errMsg[], size_t errMsg return true; } -bool Application::SaveFont(StripCommand strip, wchar_t errMsg[], size_t errMsgLen) +bool Application::OpenMemFont(void* font, uint32_t fontLen, wchar_t errMsg[], size_t errMsgLen) { - return this->SaveFont(this->fileName, strip, errMsg, errMsgLen); + this->charCode = this->glyphIndex = INVALID_GLYPH_INDEX; + + if (!this->font->Read(font, fontLen, this->glyph.get(), &this->platformID, &this->encodingID, errMsg, errMsgLen)) + return false; + + return true; } bool Application::SaveFont(std::string fileN, StripCommand strip, wchar_t errMsg[], size_t errMsgLen) @@ -89,6 +94,13 @@ bool Application::SaveFont(std::string fileN, StripCommand strip, wchar_t errMsg auto file = std::make_unique(); errMsg[0] = 0; + if (fileN.empty()) + { + fileN = this->fileName; + if (fileN.empty()) + return false; + } + if (!this->BuildFont(strip, errMsg, errMsgLen)) return false; @@ -104,6 +116,65 @@ bool Application::SaveFont(std::string fileN, StripCommand strip, wchar_t errMsg return true; } +bool Application::SaveMemFont(void* font, uint32_t fontLen, StripCommand strip, wchar_t errMsg[], size_t errMsgLen) +{ + errMsg[0] = 0; + + if (!this->BuildFont(strip, errMsg, errMsgLen)) + return false; + + return this->font->Write(font, fontLen, errMsg, errMsgLen); +} + +bool Application::GetMemFont(void* font, uint32_t fontLen, wchar_t errMsg[], size_t errMsgLen) +{ + errMsg[0] = 0; + + return this->font->Write(font, fontLen, errMsg, errMsgLen); +} + +uint32_t Application::GetFontSize() +{ + return this->font->Size(); +} + +bool Application::ImportSourceFromBinary(wchar_t errMsg[], size_t errMsgLen) +{ + bool done = true; + int32_t savedGlyph = this->glyphIndex; + errMsg[0] = 0; + + long numGlyphs = this->font->NumberOfGlyphs(); + + done = this->font->InitIncrBuildSfnt(false, errMsg, errMsgLen); + this->font->InheritProfiles(); + + done = done && this->font->GetPrepFromBin(this->prep.get(), errMsg, errMsgLen); + done = done && this->font->GetFpgmFromBin(this->fpgm.get(), errMsg, errMsgLen); + + for (int32_t glyphID = 0; glyphID < numGlyphs && done; glyphID++) + { + this->glyphIndex = glyphID; + + done = done && this->font->GetGlyph(glyphID, this->glyph.get(), errMsg, errMsgLen); + + done = done && this->font->GetGlyf(glyphID, this->glyf.get(), errMsg, errMsgLen); + done = done && this->font->GetTalk(glyphID, this->talk.get(), errMsg, errMsgLen); + + done = done && this->font->GetGlyfFromBin(glyphID, this->talk.get(), this->glyf.get(), this->glyph.get(), errMsg, errMsgLen); + + if (done) + done = this->font->AddGlyphToNewSfnt(this->font->CharGroupOf(glyphID), glyphID, this->glyph.get(), this->font->GlyfBinSize(), this->font->GlyfBin(), this->glyf.get(), this->talk.get(), errMsg, errMsgLen); + + } + + done = this->font->TermIncrBuildSfnt(!done, this->prep.get(), this->cpgm.get(), this->fpgm.get(), errMsg, errMsgLen); + + this->GotoGlyph(savedGlyph, true); + + return done; +} + bool Application::GotoFont(wchar_t errMsg[], size_t errMsgLen) { int32_t errPos, errLen; bool legacy = false; @@ -406,7 +477,7 @@ bool Application::CompileAll(bool quiet, bool legacy, bool variationCompositeGua done = this->font->UpdateBinData(asmFPGM, binSize, binData); else { done = this->font->UpdateBinData(asmFPGM, 0, NULL); - swprintf(tempErrMsg, sizeof(tempErrMsg)/sizeof(tempErrMsg), L"Font Pgm, line %li: " WIDE_STR_FORMAT, this->fpgm->LineNumOf(errPos), compErrMsg); + swprintf(tempErrMsg, sizeof(tempErrMsg)/sizeof(wchar_t), L"Font Pgm, line %li: " WIDE_STR_FORMAT, this->fpgm->LineNumOf(errPos), compErrMsg); errBuf->AppendLine(tempErrMsg); } } @@ -511,4 +582,4 @@ char* Application::wCharToChar(char out[], const wchar_t in[]) } return out; -} \ No newline at end of file +} diff --git a/src/application.h b/src/application.h index 9e5f48b..da711e8 100644 --- a/src/application.h +++ b/src/application.h @@ -10,8 +10,14 @@ class Application virtual ~Application(void); bool OpenFont(std::string fileName, wchar_t errMsg[], size_t errMsgLen); - bool SaveFont(StripCommand strip, wchar_t errMsg[], size_t errMsgLen); + bool OpenMemFont(void* font, uint32_t fontLen, wchar_t errMsg[], size_t errMsgLen); + bool SaveFont(std::string fileName, StripCommand strip, wchar_t errMsg[], size_t errMsgLen); + bool SaveMemFont(void* font, uint32_t fontLen, StripCommand strip, wchar_t errMsg[], size_t errMsgLen); + bool GetMemFont(void* font, uint32_t fontLen, wchar_t errMsg[], size_t errMsgLen); + uint32_t GetFontSize(); + + bool ImportSourceFromBinary(wchar_t errMsg[], size_t errMsgLen); bool GotoFont(wchar_t errMsg[], size_t errMsgLen); bool GotoGlyph(int32_t code, bool isGlyphIndex); diff --git a/src/pch.h b/src/pch.h index 37c0a43..23303a3 100644 --- a/src/pch.h +++ b/src/pch.h @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include @@ -40,6 +42,7 @@ #include "TTGenerator.h" #include "CvtManager.h" #include "TMTParser.h" +#include "ttiua.h" #define STRCPYW wcscpy diff --git a/src/ttiua.cpp b/src/ttiua.cpp new file mode 100644 index 0000000..20a2fd7 --- /dev/null +++ b/src/ttiua.cpp @@ -0,0 +1,406 @@ + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "pch.h" + +const wchar_t *gszVTTInstructionStr[256] = + { + /***** 0x00 - 0x0f *****/ + L"SVTCA[Y]", + L"SVTCA[X]", + L"SPVTCA[Y]", + L"SPVTCA[X]", + L"SFVTCA[Y]", + L"SFVTCA[X]", + L"SPVTL[r]", + L"SPVTL[R]", + L"SFVTL[r]", + L"SFVTL[R]", + L"SPVFS[]", + L"SFVFS[]", + L"GPV[]", + L"GFV[]", + L"SFVTPV[]", + L"ISECT[]", + + /***** 0x10 - 0x1f *****/ + L"SRP0[]", + L"SRP1[]", + L"SRP2[]", + L"SZP0[]", + L"SZP1[]", + L"SZP2[]", + L"SZPS[]", + L"SLOOP[]", + L"RTG[]", + L"RTHG[]", + L"SMD[]", + L"ELSE[]", + L"JMPR[]", + L"SCVTCI[]", + L"SSWCI[]", + L"SSW[]", + + /***** 0x20 - 0x2f *****/ + L"DUP[]", + L"POP[]", + L"CLEAR[]", + L"SWAP[]", + L"DEPTH[]", + L"CINDEX[]", + L"MINDEX[]", + L"ALIGNPTS[]", + L"RAW[]", + L"UTP[]", + L"LOOPCALL[]", + L"CALL[]", + L"FDEF[]", + L"ENDF[]", + L"MDAP[r]", + L"MDAP[R]", + + + /***** 0x30 - 0x3f *****/ + L"IUP[Y]", + L"IUP[X]", + L"SHP[2]", + L"SHP[1]", + L"SHC[2]", + L"SHC[1]", + L"SHZ[2]", + L"SHZ[1]", + L"SHPIX[]", + L"IP[]", + L"MSIRP[m]", + L"MSIRP[M]", + L"ALIGNRP[]", + L"RTDG[]", + L"MIAP[r]", + L"MIAP[R]", + + /***** 0x40 - 0x4f *****/ + L"NPUSHB[]", + L"NPUSHW[]", + L"WS[]", + L"RS[]", + L"WCVTP[]", + L"RCVT[]", + L"GC[N]", + L"GC[O]", + L"SCFS[]", + L"MD[N]", + L"MD[O]", + L"MPPEM[]", + L"MPS[]", + L"FLIPON[]", + L"FLIPOFF[]", + L"DEBUG[]", + + /***** 0x50 - 0x5f *****/ + L"LT[]", + L"LTEQ[]", + L"GT[]", + L"GTEQ[]", + L"EQ[]", + L"NEQ[]", + L"ODD[]", + L"EVEN[]", + L"IF[]", + L"EIF[]", + L"AND[]", + L"OR[]", + L"NOT[]", + L"DELTAP1[]", + L"SDB[]", + L"SDS[]", + + /***** 0x60 - 0x6f *****/ + L"ADD[]", + L"SUB[]", + L"DIV[]", + L"MUL[]", + L"ABS[]", + L"NEG[]", + L"FLOOR[]", + L"CEILING[]", + L"ROUND[Gr]", + L"ROUND[Bl]", + L"ROUND[Wh]", + L"/* ROUND[3?] */", + L"NROUND[Gr]", + L"NROUND[Bl]", + L"NROUND[Wh]", + L"/* NROUND[3?] */", + + /***** 0x70 - 0x7f *****/ + L"WCVTF[]", + L"DELTAP2[]", + L"DELTAP3[]", + L"DELTAC1[]", + L"DELTAC2[]", + L"DELTAC3[]", + L"SROUND[]", + L"S45ROUND[]", + L"JROT[]", + L"JROF[]", + L"ROFF[]", + L"USER7B[]", + L"RUTG[]", + L"RDTG[]", + L"SANGW[]", + L"AA[]", + + /***** 0x80 - 0x8d *****/ + L"FLIPPT[]", + L"FLIPRGON[]", + L"FLIPRGOFF[]", + L"USER83[]", + L"USER84[]", + L"SCANCTRL[]", + L"SDPVTL[r]", + L"SDPVTL[R]", + L"GETINFO[]", + L"IDEF[]", + L"ROLL[]", + L"MAX[]", + L"MIN[]", + L"SCANTYPE[]", + L"INSTCTRL[]", + + /***** 0x8f - 0xaf *****/ + L"USER8f[]", + L"USER90[]", + L"USER91[]", + L"USER92[]", + L"USER93[]", + L"USER94[]", + L"USER95[]", + L"USER96[]", + L"USER97[]", + L"USER98[]", + L"USER99[]", + L"USER9A[]", + L"USER9B[]", + L"USER9C[]", + L"USER9D[]", + L"USER9E[]", + L"USER9F[]", + L"USERA0[]", + L"USERA1[]", + L"USERA2[]", + L"USERA3[]", + L"USERA4[]", + L"USERA5[]", + L"USERA6[]", + L"USERA7[]", + L"USERA8[]", + L"USERA9[]", + L"USERAA[]", + L"USERAB[]", + L"USERAC[]", + L"USERAD[]", + L"USERAE[]", + L"USERAF[]", + + /***** 0xb0 - 0xb7 *****/ + L"PUSHB[1]", + L"PUSHB[2]", + L"PUSHB[3]", + L"PUSHB[4]", + L"PUSHB[5]", + L"PUSHB[6]", + L"PUSHB[7]", + L"PUSHB[8]", + + /***** 0xb8 - 0xbf *****/ + L"PUSHW[1]", + L"PUSHW[2]", + L"PUSHW[3]", + L"PUSHW[4]", + L"PUSHW[5]", + L"PUSHW[6]", + L"PUSHW[7]", + L"PUSHW[8]", + + /***** 0xc0 - 0xdf *****/ + L"MDRP[mrGr]", + L"MDRP[m>rBl]", + L"MDRP[m>rWh]", + L"/* MDRP[m>r3] */", + L"MDRP[m>RGr]", + L"MDRP[m>RBl]", + L"MDRP[m>RWh]", + L"/* MDRP[m>R3] */", + L"MDRP[MrGr]", + L"MDRP[M>rBl]", + L"MDRP[M>rWh]", + L"/* MDRP[M>r3] */", + L"MDRP[M>RGr]", + L"MDRP[M>RBl]", + L"MDRP[M>RWh]", + L"/* MDRP[M>R3] */", + + /***** 0xe0 - 0xff *****/ + L"MIRP[mrGr]", + L"MIRP[m>rBl]", + L"MIRP[m>rWh]", + L"/* MIRP[m>r3] */", + L"MIRP[m>RGr]", + L"MIRP[m>RBl]", + L"MIRP[m>RWh]", + L"/* MIRP[m>R3] */", + L"MIRP[MrGr]", + L"MIRP[M>rBl]", + L"MIRP[M>rWh]", + L"/* MIRP[M>r3] */", + L"MIRP[M>RGr]", + L"MIRP[M>RBl]", + L"MIRP[M>RWh]", + L"/* MIRP[M>R3] */" }; + +/**********************************************************************/ + +void TTIUnAsm(unsigned char* pbyInst, unsigned short uIlen, TextBuffer* dest, bool clear, bool asmBlock) +{ + unsigned short i; + + unsigned char byInst; + unsigned short uloc; + unsigned short ucnt; + short nval; + unsigned char *pbyIP; + wchar_t szOutBuffer[256]; + + if( clear ) + { + dest->SetText(0,L""); + } + + if( uIlen == 0 ) + { + // nada! + return; + } + + if(asmBlock) + dest->Append(L"ASM(\"" BRK L"#PUSHOFF" BRK); + else + dest->Append(L"#PUSHOFF" BRK); + + + pbyIP = pbyInst; + uloc = 0; + while ( pbyIP < pbyInst+uIlen ) + { + byInst = *pbyIP++; + + /* format and print instruction */ + swprintf(szOutBuffer,sizeof(szOutBuffer)/sizeof(wchar_t), WIDE_STR_FORMAT, gszVTTInstructionStr[byInst] ); + + dest->Append(szOutBuffer); + + /* deal with any instruction arguments */ + if( byInst >= 0xb0 && byInst <= 0xb7 ) /* PUSHB[abc] args */ + { + /* display PUSHB arguments */ + ucnt = (unsigned short) (byInst - 0xaf); + for( i=0; iAppend(szOutBuffer); + uloc++; + } + } + else if( byInst >= 0xb8 && byInst <= 0xbf ) /* PUSHW[abc] args */ + { + /* display PUSHW arguments */ + ucnt = (unsigned short) (byInst - 0xb7); + for( i=0; iAppend(szOutBuffer); + } + } + else if( byInst == 0x40 ) /* NPUSHB[] */ + { + /* display NPUSHB arguments */ + ucnt = *pbyIP++; + swprintf(szOutBuffer, sizeof(szOutBuffer) / sizeof(wchar_t), L", %u", ucnt); + dest->Append(szOutBuffer); + uloc++; + + for( i=0; iAppend(szOutBuffer); + uloc++; + } + } + else if( byInst == 0x41 ) /* NPUSHW[] */ + { + /* display NPUSHW arguments */ + ucnt = *pbyIP++; + swprintf(szOutBuffer, sizeof(szOutBuffer) / sizeof(wchar_t), L", %u", ucnt); + dest->Append(szOutBuffer); + uloc++; + + for( i=0; iAppend(szOutBuffer); + } + } + + dest->Append(BRK); + uloc ++; /* update location */ + } + + if(asmBlock) + dest->Append(L"#PUSHON" BRK L"\")" BRK); + else + dest->Append(L"#PUSHON" BRK); + +} /* TTIUnAsm() */ diff --git a/src/ttiua.h b/src/ttiua.h new file mode 100644 index 0000000..9e962c9 --- /dev/null +++ b/src/ttiua.h @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#ifndef TTIUA_DOT_H_DEFINED +#define TTIUA_DOT_H_DEFINED + +void TTIUnAsm(unsigned char* pbyInst, unsigned short uIlen, TextBuffer* dest, bool clear, bool asmBlock); + +#endif /* TTIUA_DOT_H_DEFINED */ diff --git a/src/vttcompile.cpp b/src/vttcompile.cpp index 40f779a..ab4a55e 100644 --- a/src/vttcompile.cpp +++ b/src/vttcompile.cpp @@ -17,6 +17,7 @@ int ShowUsage(wchar_t* strErr) wprintf(L"ERROR: " WIDE_STR_FORMAT L"\n\n", strErr); } wprintf(L"USAGE: vttcompile [options] [out.ttf] \n"); + wprintf(L"\t-i import source from binary \n"); wprintf(L"\t-a compile everything \n"); wprintf(L"\t-gXXXX compile everything for glyph id (base 10) \n"); wprintf(L"\t-rXXXX compile everything for glyph range starting with glyph specified \n\t with -g up to and including glyph specified with -r \n "); @@ -45,6 +46,7 @@ int main(int argc, char* argv[]) uint32_t g1 = 0, g2 = 0; bool haveGlyph = false; bool haveRange = false; + bool bSourceFromBinary = false; int argOffset = 0; @@ -61,7 +63,7 @@ int main(int argc, char* argv[]) if (argc == 1) return ShowUsage(NULL); - CommandLineOptions cmd(argc, argv, "?HhAaBbSsCcqQLlVvg:G:r:R"); + CommandLineOptions cmd(argc, argv, "?HhAaBbSsCcqQIiLlVvg:G:r:R"); while ((c = cmd.GetOption()) != END) { @@ -102,6 +104,11 @@ int main(int argc, char* argv[]) bVariationCompositeGuard = false; break; + case 'I': + case 'i': + bSourceFromBinary = true; + break; + case 'g': case 'G': sg1 = cmd.GetOptionArgument(); @@ -185,6 +192,18 @@ int main(int argc, char* argv[]) exit(EXIT_FAILURE); } + if (bSourceFromBinary) + { + if (!application->ImportSourceFromBinary(errMsg, sizeof(errMsg) / sizeof(wchar_t))) + { + fwprintf(stderr, errMsg); + fwprintf(stderr, L"\n"); + fwprintf(stderr, L"Can not complete import operation! \n"); + fwprintf(stderr, L"\n"); + exit(EXIT_FAILURE); + } + } + if (bCompileAll) { if (!application->CompileAll(bQuiet, bLegacy, bVariationCompositeGuard, errMsg, sizeof(errMsg) / sizeof(wchar_t))) diff --git a/tests/test_vttcompile.py b/tests/test_vttcompile.py index 43d8e58..1e25c79 100644 --- a/tests/test_vttcompile.py +++ b/tests/test_vttcompile.py @@ -8,30 +8,91 @@ TESTDATA = Path(__file__).parent / "data" IN_SELAWIK = TESTDATA / "Selawik-variable.ttf" -OUT_COMPILED = TESTDATA / "out_c.ttf" -OUT_COMPILED_STRIPPED = TESTDATA / "out_c_s.ttf" - -compiler = vtt.Compiler(IN_SELAWIK) -compiler.compile_all() -compiler.save_font(OUT_COMPILED, vtt.StripLevel.STRIP_NOTHING) -compiler.save_font(OUT_COMPILED_STRIPPED, vtt.StripLevel.STRIP_SOURCE) @pytest.fixture def original_font(): return TTFont(IN_SELAWIK) @pytest.fixture -def compiled_font(): - return TTFont(OUT_COMPILED) +def compiled_font_file(): + compiler = vtt.Compiler(IN_SELAWIK) + compiler.compile_all() + out_compiled = TESTDATA / "out_c1.ttf" + compiler.save_font(out_compiled, vtt.StripLevel.STRIP_NOTHING) + return TTFont(out_compiled) + +@pytest.fixture +def compiled_font_file_str(): + in_selawik_str = str(IN_SELAWIK) + compiler = vtt.Compiler(in_selawik_str) + compiler.compile_all() + out_compiled_str = str(TESTDATA / "out_c2.ttf") + compiler.save_font(out_compiled_str, vtt.StripLevel.STRIP_NOTHING) + return TTFont(out_compiled_str) @pytest.fixture -def compiled_stripped_font(): - return TTFont(OUT_COMPILED_STRIPPED) +def compiled_font_mem(): + tt = TTFont(IN_SELAWIK) + compiler = vtt.Compiler(tt) + compiler.compile_all() + tt1 = compiler.get_ttfont(vtt.StripLevel.STRIP_NOTHING) + return tt1 -def test_compiled(original_font, tmp_path: Path, compiled_font): - ttorig = original_font - ttcomp = compiled_font +@pytest.fixture +def compiled_font_file_mem(): + compiler = vtt.Compiler(IN_SELAWIK) + compiler.compile_all() + tt1 = compiler.get_ttfont(vtt.StripLevel.STRIP_NOTHING) + return tt1 + +@pytest.fixture +def compiled_font_mem_file(): + tt = TTFont(IN_SELAWIK) + compiler = vtt.Compiler(tt) + compiler.compile_all() + out_compiled = TESTDATA / "out_c3.ttf" + compiler.save_font(out_compiled, vtt.StripLevel.STRIP_NOTHING) + return TTFont(out_compiled) +@pytest.fixture +def compiled_stripped_font_file(): + compiler = vtt.Compiler(IN_SELAWIK) + compiler.compile_all() + out_compiled_stripped = TESTDATA / "out_c_s1.ttf" + compiler.save_font(out_compiled_stripped, vtt.StripLevel.STRIP_SOURCE) + return TTFont(out_compiled_stripped) + +@pytest.fixture +def compiled_stripped_font_mem(): + tt = TTFont(IN_SELAWIK) + compiler = vtt.Compiler(tt) + compiler.compile_all() + tt1 = compiler.get_ttfont(vtt.StripLevel.STRIP_SOURCE) + return tt1 + +@pytest.fixture +def compiled_source_from_bin_font_file(): + compiler = vtt.Compiler(IN_SELAWIK) + compiler.import_source_from_binary() + out_import = TESTDATA / "out_c_c4i.ttf" + compiler.save_font(out_import, vtt.StripLevel.STRIP_NOTHING) + compiler.compile_all() + out_import_compiled = TESTDATA / "out_c_c4.ttf" + compiler.save_font(out_import_compiled, vtt.StripLevel.STRIP_NOTHING) + return TTFont(out_import_compiled) + + +@pytest.fixture +def compiled_source_from_bin_font_mem(): + tt = TTFont(IN_SELAWIK) + compiler = vtt.Compiler(tt) + compiler.import_source_from_binary() + compiler.compile_all() + tt1 = compiler.get_ttfont(vtt.StripLevel.STRIP_NOTHING) + return tt1 + + +def compare_fonts(ttorig, ttcomp) -> None: assert ttorig['maxp'].numGlyphs == ttcomp['maxp'].numGlyphs assert ttorig['maxp'] == ttcomp['maxp'] assert ttorig['fpgm'] == ttcomp['fpgm'] @@ -56,11 +117,7 @@ def test_compiled(original_font, tmp_path: Path, compiled_font): print(comp_assembly) assert orig_assembly == comp_assembly - -def test_stripped(original_font, tmp_path: Path, compiled_stripped_font): - ttorig = original_font - ttstrip = compiled_stripped_font - +def check_stripped(ttorig, ttstrip) -> None: assert("TSI0" in ttorig) assert("TSI0" not in ttstrip) @@ -76,10 +133,31 @@ def test_stripped(original_font, tmp_path: Path, compiled_stripped_font): assert("TSI5" in ttorig) assert("TSI5" not in ttstrip) - +def test_compiled_file_file_path(original_font, tmp_path: Path, compiled_font_file): + compare_fonts(original_font, compiled_font_file) + +def test_compiled_file_file_str(original_font, tmp_path: Path, compiled_font_file_str): + compare_fonts(original_font, compiled_font_file_str) + +def test_stripped_file_file(original_font, tmp_path: Path, compiled_stripped_font_file): + check_stripped(original_font, compiled_stripped_font_file) + +def test_compiled_file_mem(original_font, compiled_font_file_mem): + compare_fonts(original_font, compiled_font_file_mem) +def test_compiled_mem_file(original_font, compiled_font_mem_file): + compare_fonts(original_font, compiled_font_mem_file) +def test_compile_mem_mem(original_font, compiled_font_mem): + compare_fonts(original_font, compiled_font_mem) +def test_stripped_mem_mem(original_font, compiled_stripped_font_mem): + check_stripped(original_font, compiled_stripped_font_mem) +def test_import_source_from_binary_file(original_font, compiled_source_from_bin_font_file): + compare_fonts(original_font, compiled_source_from_bin_font_file) +def test_import_source_from_binary_mem(original_font, compiled_source_from_bin_font_mem): + compare_fonts(original_font, compiled_source_from_bin_font_mem) + \ No newline at end of file diff --git a/vttcompile/CMakeLists.txt b/vttcompile/CMakeLists.txt index c96e2c6..952a435 100644 --- a/vttcompile/CMakeLists.txt +++ b/vttcompile/CMakeLists.txt @@ -52,6 +52,7 @@ set(Header_Files "../src/VariationModels.h" "../src/vttcompile.h" "../src/application.h" + "../src/ttiua.h" ) source_group("Header Files" FILES ${Header_Files}) @@ -73,6 +74,7 @@ set(Source_Files "../src/VariationModels.cpp" "../src/vttcompile.cpp" "../src/application.cpp" + "../src/ttiua.cpp" ) source_group("Source Files" FILES ${Source_Files}) diff --git a/vttcompile/vttcompile.vcxproj b/vttcompile/vttcompile.vcxproj index 7eafc74..1598183 100644 --- a/vttcompile/vttcompile.vcxproj +++ b/vttcompile/vttcompile.vcxproj @@ -1,189 +1,191 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {c163eacb-185d-4f8d-9de4-532e41c0024b} - vttcompile - 10.0 - - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - false - - - true - - - false - - - - Level3 - true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - - - - - Level3 - true - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - - - Console - true - true - true - - - - - Level3 - true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ..\src - stdcpp20 - - - Console - true - - - - - Level3 - true - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ..\src - stdcpp20 - - - Console - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {c163eacb-185d-4f8d-9de4-532e41c0024b} + vttcompile + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\src + stdcpp20 + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..\src + stdcpp20 + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vttcompile/vttcompile.vcxproj.filters b/vttcompile/vttcompile.vcxproj.filters index fdc557d..80ca9e8 100644 --- a/vttcompile/vttcompile.vcxproj.filters +++ b/vttcompile/vttcompile.vcxproj.filters @@ -1,132 +1,138 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/vttcompile/vttcompile.xcodeproj/project.pbxproj b/vttcompile/vttcompile.xcodeproj/project.pbxproj index 8cfc135..9c00728 100644 --- a/vttcompile/vttcompile.xcodeproj/project.pbxproj +++ b/vttcompile/vttcompile.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 567685F62707D39F00391506 /* TTEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 567685E32707D39F00391506 /* TTEngine.cpp */; }; 567685F72707D39F00391506 /* vttcompile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 567685E42707D39F00391506 /* vttcompile.cpp */; }; 567685F82707D39F00391506 /* Variation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 567685E62707D39F00391506 /* Variation.cpp */; }; + 7A06FC33295263DD00470945 /* ttiua.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A06FC312952633800470945 /* ttiua.cpp */; }; 7A45EDB3274323060005BB8F /* application.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A45EDB1274321BD0005BB8F /* application.cpp */; }; /* End PBXBuildFile section */ @@ -77,6 +78,8 @@ 567685E52707D39F00391506 /* Platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Platform.h; sourceTree = ""; }; 567685E62707D39F00391506 /* Variation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Variation.cpp; sourceTree = ""; }; 567685E72707D39F00391506 /* opentypedefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opentypedefs.h; sourceTree = ""; }; + 7A06FC312952633800470945 /* ttiua.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ttiua.cpp; sourceTree = ""; }; + 7A06FC322952633800470945 /* ttiua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ttiua.h; sourceTree = ""; }; 7A45EDB1274321BD0005BB8F /* application.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = application.cpp; sourceTree = ""; }; 7A45EDB2274321BD0005BB8F /* application.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = application.h; sourceTree = ""; }; /* End PBXFileReference section */ @@ -111,6 +114,8 @@ 567685B92707D35100391506 /* vttcompile */ = { isa = PBXGroup; children = ( + 7A06FC312952633800470945 /* ttiua.cpp */, + 7A06FC322952633800470945 /* ttiua.h */, 7A45EDB1274321BD0005BB8F /* application.cpp */, 7A45EDB2274321BD0005BB8F /* application.h */, 567685DE2707D39F00391506 /* CvtManager.cpp */, @@ -212,6 +217,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 7A06FC33295263DD00470945 /* ttiua.cpp in Sources */, 567685F02707D39F00391506 /* File.cpp in Sources */, 567685F82707D39F00391506 /* Variation.cpp in Sources */, 567685F12707D39F00391506 /* TTGenerator.cpp in Sources */, diff --git a/vttcompilepy/__init__.py b/vttcompilepy/__init__.py index 9d24135..7abc6e9 100644 --- a/vttcompilepy/__init__.py +++ b/vttcompilepy/__init__.py @@ -1 +1,6 @@ -from .vttcompilepy import * \ No newline at end of file +from .vttcompilepy import * + +try: + from ._version import version as __version__ +except ImportError: + __version__ = "0.0.0+unknown" \ No newline at end of file diff --git a/vttcompilepy/__main__.py b/vttcompilepy/__main__.py index 7c32695..a264fa7 100644 --- a/vttcompilepy/__main__.py +++ b/vttcompilepy/__main__.py @@ -3,19 +3,24 @@ import argparse import sys from pathlib import Path +from . import __version__ as vtt_version def main(args=None): if args is None: args = sys.argv[1:] parser = argparse.ArgumentParser() + parser.add_argument('--version', action='version', version='%(prog)s {version}'.format(version=vtt_version)) + parser.add_argument("input", help="Input file") parser.add_argument("output", help="Output file") + parser.add_argument("-i", "--importsourcefrombinary", action="store_true", help ="Import source from binary") + cgroup = parser.add_argument_group("Compile options") cgroup.add_argument("-a", "--all", action="store_true", help ="Compile everything") cgroup.add_argument("-l", "--legacy", action="store_true", help ="Rare cases for very old fonts") - cgroup.add_argument("-v", "--variationcompositeguard", action="store_true", help ="Disable variation composite guard (default: enabled)") + cgroup.add_argument("-v", "--disablevariationcompositeguard", action="store_true", help ="Disable variation composite guard (default: enabled)") sgroup = parser.add_argument_group("Strip options") sgroup.add_argument("-s", "--source", action="store_true", help="Strip source") @@ -37,9 +42,12 @@ def main(args=None): if args.legacy: legacy = True - if args.variationcompositeguard: + if args.disablevariationcompositeguard: variationCompositeGuard = False + if args.importsourcefrombinary: + compiler.import_source_from_binary() + if args.all: compiler.compile_all(legacy, variationCompositeGuard) diff --git a/vttcompilepy/_version.py b/vttcompilepy/_version.py new file mode 100644 index 0000000..4cfc22c --- /dev/null +++ b/vttcompilepy/_version.py @@ -0,0 +1 @@ +__version__ = version = '0.0.1.6' \ No newline at end of file diff --git a/vttcompilepy/cvttcompilepy.pxd b/vttcompilepy/cvttcompilepy.pxd index 84760a5..cd60c20 100644 --- a/vttcompilepy/cvttcompilepy.pxd +++ b/vttcompilepy/cvttcompilepy.pxd @@ -20,8 +20,14 @@ cdef extern from "application.h": Application() except + bool Create() bool OpenFont(string fileName, wchar_t* errMsg, size_t errMsgLen) - bool SaveFont(StripCommand strip, wchar_t* errMsg, size_t errMsgLen) + bool OpenMemFont(void* font, uint32_t fontLen, wchar_t* errMsg, size_t errMsgLen) + bool SaveFont(string fileName, StripCommand strip, wchar_t* errMsg, size_t errMsgLen) + bool SaveMemFont(void* font, uint32_t fontLen, wchar_t* errMsg, size_t errMsgLen) + bool GetMemFont(void* font, uint32_t fontLen, wchar_t* errMsg, size_t errMsgLen) + uint32_t GetFontSize() + + bool ImportSourceFromBinary(wchar_t* errMsg, size_t errMsgLen) bool GotoFont(wchar_t* errMsg, size_t errMsgLen) @@ -29,3 +35,5 @@ cdef extern from "application.h": bool CompileAll(bool quiet, bool legacy, bool variationCompositeGuard, wchar_t* errMsg, size_t errMsgLen) char* wCharToChar(char* out1, const wchar_t* in1) + + bool BuildFont(StripCommand strip, wchar_t* errMsg, size_t errMsgLen); diff --git a/vttcompilepy/vttcompilepy.pyx b/vttcompilepy/vttcompilepy.pyx index b4261cd..76a2fae 100644 --- a/vttcompilepy/vttcompilepy.pyx +++ b/vttcompilepy/vttcompilepy.pyx @@ -3,6 +3,12 @@ from enum import IntEnum from .cvttcompilepy cimport * from pathlib import Path +from io import BytesIO +import pathlib +import fontTools +from fontTools import ttLib +from cpython cimport array +import array DEF ERR_BUF_SIZE = 1024 @@ -18,26 +24,60 @@ class StripLevel(IntEnum): cdef class Compiler: cdef Application* app_ # Hold C++ instance + + def __cinit__(self, font): + self.app_ = new Application() + self.app_.Create() + cdef wchar_t werr[ERR_BUF_SIZE] + cdef char err[ERR_BUF_SIZE] + cdef array.array a = array.array('B') + if(type(font)) == str: + font = Path(font) + # path input case + if isinstance(font, pathlib.PurePath): + src = bytes(font) + result = self.app_.OpenFont(src, werr, ERR_BUF_SIZE) + if result != True: + raise FileNotFoundError(self.app_.wCharToChar(err, werr)) + result = self.app_.GotoFont(werr, ERR_BUF_SIZE) + if result != True: + raise FileNotFoundError(self.app_.wCharToChar(err, werr)) + # fontTools TTFont input case + elif isinstance(font,fontTools.ttLib.ttFont.TTFont): + font_image = BytesIO() + font.save(font_image) + font_size = font_image.getbuffer().nbytes + # memoryview of font_image + rawbytes = font_image.getbuffer() + # array.array of memoryview + a.frombytes(rawbytes) + result = self.app_.OpenMemFont(a.data.as_voidptr,font_size,werr,ERR_BUF_SIZE) + if result != True: + raise FileNotFoundError(self.app_.wCharToChar(err,werr)) + result = self.app_.GotoFont(werr, ERR_BUF_SIZE) + if result != True: + raise FileNotFoundError(self.app_.wCharToChar(err,werr)) + else: + raise ValueError("Parameter not valid") - #def __cinit__(self): - # self.app_ = new Application() + @classmethod + def from_file(cls, file): + return cls(file) - def __cinit__(self, path: Path): - self.app_ = new Application() - self.app_.Create() - cdef string src = bytes(path) - cdef wchar_t werr[ERR_BUF_SIZE] - cdef char err[ERR_BUF_SIZE] - result = self.app_.OpenFont(src, werr, ERR_BUF_SIZE) - if result != True: - raise FileNotFoundError(self.app_.wCharToChar(err, werr)) - result = self.app_.GotoFont(werr, ERR_BUF_SIZE) - if result != True: - raise FileNotFoundError(self.app_.wCharToChar(err, werr)) + @classmethod + def from_ttfont(cls, font): + return cls(font) - def __dealloc__(self): + def __dealloc__(self): del self.app_ + def import_source_from_binary(self) -> None: + cdef wchar_t werr[ERR_BUF_SIZE] + cdef char err[ERR_BUF_SIZE] + result = self.app_.ImportSourceFromBinary(werr, ERR_BUF_SIZE) + if(result != True): + raise ImportError(self.app_.wCharToChar(err, werr)) + def compile_all(self, legacy: bint = False, variationCompositeGuard: bint = True) -> None: cdef wchar_t werr[ERR_BUF_SIZE] cdef char err[ERR_BUF_SIZE] @@ -52,23 +92,46 @@ cdef class Compiler: if(result != True): raise CompileError(self.app_.wCharToChar(err, werr)) - def save_font(self, path: Path = None, level: StripLevel = None) -> None: + def get_ttfont(self, level: StripLevel = None): cdef char err[ERR_BUF_SIZE] cdef wchar_t werr[ERR_BUF_SIZE] - cdef string dest + cdef array.array a = array.array('B') if(level is None): level = StripLevel.STRIP_NOTHING - if(path is None): - result = self.app_.SaveFont(level, werr, ERR_BUF_SIZE) - if(result != True): - raise FileNotFoundError(self.app_.wCharToChar(err, werr)) - else: - dest = bytes(path) - result = self.app_.SaveFont(dest, level, werr, ERR_BUF_SIZE) - if(result != True): - raise FileNotFoundError(self.app_.wCharToChar(err, werr)) + # build step separately so we can get size of final image for resize of array + result = self.app_.BuildFont( level, werr, ERR_BUF_SIZE) + if(result != True): + raise FileNotFoundError(self.app_.wCharToChar(err, werr)) + + size = self.app_.GetFontSize() + array.resize(a, size) + + result = self.app_.GetMemFont(a.data.as_voidptr, size, werr, ERR_BUF_SIZE) + if(result != True): + raise FileNotFoundError(self.app_.wCharToChar(err, werr)) + + b = BytesIO(a.tobytes()) + + return ttLib.TTFont(b) + + def save_font(self, file = None, level: StripLevel = None) -> None: + cdef char err[ERR_BUF_SIZE] + cdef wchar_t werr[ERR_BUF_SIZE] + cdef string dest + + if(level is None): + level = StripLevel.STRIP_NOTHING + + if(file is not None): + if(type(file)) == str: + file = Path(file) + dest = bytes(file) + + result = self.app_.SaveFont(dest, level, werr, ERR_BUF_SIZE) + if(result != True): + raise FileNotFoundError(self.app_.wCharToChar(err, werr))