From 8ce7304896e2a7dfa4674b066778c55f68b82f19 Mon Sep 17 00:00:00 2001 From: Michael Pfeiffer Date: Thu, 18 Sep 2003 20:21:06 +0000 Subject: [PATCH] Added user defined encoding that is created at runtime. Display used fonts in status window. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4758 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../print/drivers/pdf/source/Fonts.cpp | 30 ++++- src/add-ons/print/drivers/pdf/source/Fonts.h | 38 ++++++- .../print/drivers/pdf/source/PDFText.cpp | 107 ++++++++++++++---- .../print/drivers/pdf/source/PDFWriter.h | 5 + 4 files changed, 156 insertions(+), 24 deletions(-) diff --git a/src/add-ons/print/drivers/pdf/source/Fonts.cpp b/src/add-ons/print/drivers/pdf/source/Fonts.cpp index b0265f8018..d3e7a60fe8 100644 --- a/src/add-ons/print/drivers/pdf/source/Fonts.cpp +++ b/src/add-ons/print/drivers/pdf/source/Fonts.cpp @@ -31,7 +31,7 @@ THE SOFTWARE. #include #include #include "Fonts.h" - +#include "Report.h" // FontFile @@ -277,7 +277,8 @@ Fonts::LookupFontFiles(BPath path) if (entry.GetSize(&size) != B_OK) size = 1024*1024*1024; - + + REPORT(kDebug, -1, "Installed font %s -> %s", fn, name.Path()); fFontFiles.AddItem(new FontFile(fn, name.Path(), size, ft, size < 100*1024)); } // while dir.GetNextEntry()... @@ -532,3 +533,28 @@ static status_t psf_get_fontname(const char * path, char * fontname, size_t fn_s return status; } +// Implementation of UserDefinedEncodings + +UserDefinedEncodings::UserDefinedEncodings() + : fCurrentEncoding(0) + , fCurrentIndex(0) +{ + memset(fUsedMask, 0, sizeof(fUsedMask)); + memset(fEncoding, 0, sizeof(fEncoding)); + memset(fIndex, 0, sizeof(fIndex)); +} + +bool UserDefinedEncodings::Get(uint16 unicode, uint8 &encoding, uint8 &index) { + bool missing = !IsUsed(unicode); + if (missing) { + SetUsed(unicode); + fEncoding[unicode] = fCurrentEncoding; fIndex[unicode] = fCurrentIndex; + if (fCurrentIndex == 255) { + fCurrentIndex = 0; fCurrentEncoding ++; + } else { + fCurrentIndex ++; + } + } + encoding = fEncoding[unicode]; index = fIndex[unicode]; + return missing; +} diff --git a/src/add-ons/print/drivers/pdf/source/Fonts.h b/src/add-ons/print/drivers/pdf/source/Fonts.h index c264fe70b0..4a7feca568 100644 --- a/src/add-ons/print/drivers/pdf/source/Fonts.h +++ b/src/add-ons/print/drivers/pdf/source/Fonts.h @@ -59,7 +59,8 @@ enum font_encoding korean_encoding, first_cjk_encoding = japanese_encoding, no_of_cjk_encodings = korean_encoding - first_cjk_encoding + 1, - invalid_encoding, + invalid_encoding = korean_encoding + 1, + user_defined_encoding_start }; @@ -133,4 +134,39 @@ public: bool GetCJKOrder(int i, font_encoding& enc, bool& active) const; }; +class UsedFont { +private: + BString fFamily; + BString fStyle; + float fSize; + +public: + UsedFont(const char* family, const char* style, float size) : fFamily(family), fStyle(style), fSize(size) {} + + const char* GetFamily() const { return fFamily.String(); } + const char* GetStyle() const { return fStyle.String(); } + float GetSize() const { return fSize; } + + bool Equals(const char* family, const char* style, float size) const { return strcmp(GetFamily(), family) == 0 && strcmp(GetStyle(), style) == 0 && fSize == size; } +}; + + +class UserDefinedEncodings { +public: + UserDefinedEncodings(); + // returns true if new encoding and index pair + bool Get(uint16 unicode, uint8 &encoding, uint8 &index); + +private: + bool IsUsed(uint16 unicode) const { return (fUsedMask[unicode / 8] & (1 << (unicode % 8))) != 0; } + void SetUsed(uint16 unicode) { fUsedMask[unicode / 8] |= 1 << (unicode % 8); } + + uint8 fUsedMask[65536/8]; // exists an encoding and index for this code point? + uint8 fEncoding[65536]; // the encoding for each code point + uint8 fIndex[65536]; // the index for each code point + + uint8 fCurrentEncoding; + uint8 fCurrentIndex; +}; + #endif // FONTS_H diff --git a/src/add-ons/print/drivers/pdf/source/PDFText.cpp b/src/add-ons/print/drivers/pdf/source/PDFText.cpp index 5227e739c6..58e55dcc00 100644 --- a/src/add-ons/print/drivers/pdf/source/PDFText.cpp +++ b/src/add-ons/print/drivers/pdf/source/PDFText.cpp @@ -161,17 +161,50 @@ find_in_cid_tables(uint16 unicode, font_encoding &encoding, uint16 &index, font_ } +// -------------------------------------------------- +void +PDFWriter::MakeUserDefinedEncoding(uint16 unicode, uint8 &enc, uint8 &index) { + if (fUserDefinedEncodings.Get(unicode, enc, index)) { + BString s("user"); + s << (int)enc; + PDF_encoding_set_char(fPdf, s.String(), (int)index, NULL, (int)unicode); + } +} + +// -------------------------------------------------- +void +PDFWriter::RecordFont(const char* family, const char* style, float size) { + const int32 n = fUsedFonts.CountItems(); + for (int32 i = 0; i < n; i ++) { + if (fUsedFonts.ItemAt(i)->Equals(family, style, size)) return; + } + + UsedFont* font; + font = new UsedFont(family, style, size); + fUsedFonts.AddItem(font); + + REPORT(kInfo, -1, "Used font: \"%s\" \"%s\" %f", family, style, size); +} + // -------------------------------------------------- void -PDFWriter::GetFontName(BFont *font, char *fontname, bool &embed, font_encoding encoding) +PDFWriter::GetFontName(BFont *font, char *fontname) { font_family family; font_style style; font->GetFamilyAndStyle(&family, &style); - strcat(strcat(strcpy(fontname, family), "-"), style); + RecordFont(family, style, font->Size()); +} + +// -------------------------------------------------- +void +PDFWriter::GetFontName(BFont *font, char *fontname, bool &embed, font_encoding encoding) +{ + GetFontName(font, fontname); + switch (encoding) { case japanese_encoding: strcpy(fontname, "HeiseiMin-W3"); return; @@ -181,7 +214,6 @@ PDFWriter::GetFontName(BFont *font, char *fontname, bool &embed, font_encoding e strcpy(fontname, "STSong-Light"); return; case korean_encoding: strcpy(fontname, "HYGoThic-Medium"); return; - return; default:; } } @@ -231,12 +263,24 @@ PDFWriter::FindFont(char* fontName, bool embed, font_encoding encoding) if (embed) embed = EmbedFont(fontName); - REPORT(kDebug, fPage, "Create new font"); - int font = PDF_findfont(fPdf, fontName, encoding_names[encoding], embed); + BString s; + char user_defined[80]; + const char* encoding_name; + if (encoding < user_defined_encoding_start) { + encoding_name = encoding_names[encoding]; + } else { + s = "user"; + s << (int)(encoding - user_defined_encoding_start); + encoding_name = s.String(); + } + REPORT(kDebug, fPage, "Create new font, %sembed, encoding %s", embed ? "" : "do not ", encoding_name); + int font = PDF_findfont(fPdf, fontName, encoding_name, embed); if (font != -1) { REPORT(kDebug, fPage, "font created"); cache = new Font(fontName, font, encoding); fFontCache.AddItem(cache); + } else { + REPORT(kError, fPage, "Could not create font '%s'", fontName); } return font; } @@ -334,43 +378,66 @@ PDFWriter::DrawChar(uint16 unicode, const char* utf8, int16 size) // try to convert from utf8 to MacRoman encoding schema... int32 srcLen = size; int32 destLen = 1; - char dest[2] = "\0"; + char dest[3] = "\0\0"; int32 state = 0; bool embed = true; font_encoding encoding = macroman_encoding; + char fontName[B_FONT_FAMILY_LENGTH+B_FONT_STYLE_LENGTH+1]; if (convert_from_utf8(B_MAC_ROMAN_CONVERSION, utf8, &srcLen, dest, &destLen, &state, 0) != B_OK || dest[0] == 0 ) { // could not convert to MacRoman uint8 enc; uint16 index; font_encoding fenc; + + GetFontName(&fState->beFont, fontName); + embed = EmbedFont(fontName); - // is code point in the Adobe Glyph List? + REPORT(kDebug, -1, "find_encoding unicode %d\n", (int)unicode); if (find_encoding(unicode, enc, index)) { - // LOG((fLog, "encoding for %x -> %d %d\n", unicode, (int)enc, (int)index)); - // use one of the user defined encodings + // is code point in the Adobe Glyph List? + // Note if rendering the glyphs only would be desired, we could always use + // the second method below (MakeUserDefinedEncoding), but extracting text + // from the generated PDF would be almost impossible (OCR!) + REPORT(kDebug, -1, "encoding for %x -> %d %d", unicode, (int)enc, (int)index); + // use one of the user pre-defined encodings if (fState->beFont.FileFormat() == B_TRUETYPE_WINDOWS) { encoding = font_encoding(enc + tt_encoding0); } else { encoding = font_encoding(enc + t1_encoding0); } *dest = index; + } else if (embed) { + // if the font is embedded, create a user defined encoding at runtime + uint8 index; + MakeUserDefinedEncoding(unicode, enc, index); + *dest = index; + encoding = font_encoding(user_defined_encoding_start + enc); } else if (find_in_cid_tables(unicode, fenc, index, fFontSearchOrder)) { - // LOG((fLog, "cid table %d index = %d\n", (int)enc, (int)index)); + // font is not embedded use one of the CJK fonts for substitution + REPORT(kDebug, -1, "cid table %d index = %d", (int)fenc, (int)index); dest[0] = unicode / 256; dest[1] = unicode % 256; destLen = 2; encoding = fenc; embed = false; } else { - // LOG((fLog, "encoding for %x not found!\n", unicode)); + static bool found = false; + REPORT(kDebug, -1, "encoding for %x not found!", (int)unicode); + if (!found) { + found = true; + REPORT(kError, fPage, "Could not find an encoding for character with unicode %d! Message is not repeated for other unicode values.", (int)unicode); + } *dest = 0; // paint a box (is 0 a box in MacRoman) or return; // simply skip character } - } - // else LOG((fLog, "macroman srcLen=%d destLen=%d dest= %d %d!\n", srcLen, destLen, (int)dest[0], (int)dest[1])); - - char fontName[B_FONT_FAMILY_LENGTH+B_FONT_STYLE_LENGTH+1]; + } else { + REPORT(kDebug, -1, "macroman srcLen=%d destLen=%d dest= %d %d!", srcLen, destLen, (int)dest[0], (int)dest[1]); + } + + // Note we have to build the user defined encoding before it is used in PDF_find_font! + if (!MakesPDF()) return; + int font; GetFontName(&fState->beFont, fontName, embed, encoding); @@ -500,12 +567,10 @@ PDFWriter::DrawString(char *string, float escapement_nospace, float escapement_s float w = font.StringWidth(c, s); - if (MakesPDF()) { - if (IsClipping()) { - ClipChar(&font, (char*)u, c, s, w); - } else { - DrawChar(u[0]*256+u[1], c, s); - } + if (MakesPDF() && IsClipping()) { + ClipChar(&font, (char*)u, c, s, w); + } else { + DrawChar(u[0]*256+u[1], c, s); } // position of next character diff --git a/src/add-ons/print/drivers/pdf/source/PDFWriter.h b/src/add-ons/print/drivers/pdf/source/PDFWriter.h index 79abb230fc..8c77275f80 100644 --- a/src/add-ons/print/drivers/pdf/source/PDFWriter.h +++ b/src/add-ons/print/drivers/pdf/source/PDFWriter.h @@ -149,6 +149,7 @@ class PDFWriter : public PrinterDriver, public PictureIterator void ClipChar(BFont* font, const char* unicode, const char *utf8, int16 size, float width); bool EmbedFont(const char* n); status_t DeclareFonts(); + void RecordFont(const char* family, const char* style, float size); // BPicture playback handlers void Op(int number); @@ -325,6 +326,8 @@ class PDFWriter : public PrinterDriver, public PictureIterator XRefDests *fXRefDests; font_encoding fFontSearchOrder[no_of_cjk_encodings]; TextLine fTextLine; + TList fUsedFonts; + UserDefinedEncodings fUserDefinedEncodings; enum { @@ -361,8 +364,10 @@ class PDFWriter : public PrinterDriver, public PictureIterator bool StoreTranslatorBitmap(BBitmap *bitmap, const char *filename, uint32 type); + void GetFontName(BFont *font, char *fontname); void GetFontName(BFont *font, char *fontname, bool &embed, font_encoding encoding); int FindFont(char *fontname, bool embed, font_encoding encoding); + void MakeUserDefinedEncoding(uint16 unicode, uint8 &enc, uint8 &index); // alpha transparency Transparency* FindTransparency(uint8 alpha);