1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fpdfapi/render/charposlist.h"
8 
9 #include "build/build_config.h"
10 #include "core/fpdfapi/font/cpdf_cidfont.h"
11 #include "core/fpdfapi/font/cpdf_font.h"
12 #include "core/fxge/cfx_substfont.h"
13 #include "core/fxge/text_char_pos.h"
14 
GetCharPosList(pdfium::span<const uint32_t> char_codes,pdfium::span<const float> char_pos,CPDF_Font * font,float font_size)15 std::vector<TextCharPos> GetCharPosList(pdfium::span<const uint32_t> char_codes,
16                                         pdfium::span<const float> char_pos,
17                                         CPDF_Font* font,
18                                         float font_size) {
19   std::vector<TextCharPos> results;
20   results.reserve(char_codes.size());
21 
22   CPDF_CIDFont* cid_font = font->AsCIDFont();
23   bool is_vertical_writing = cid_font && cid_font->IsVertWriting();
24   bool has_to_unicode = !!font->GetFontDict()->GetStreamFor("ToUnicode");
25   for (size_t i = 0; i < char_codes.size(); ++i) {
26     uint32_t char_code = char_codes[i];
27     if (char_code == static_cast<uint32_t>(-1))
28       continue;
29 
30     bool is_vertical_glyph = false;
31     results.emplace_back();
32     TextCharPos& text_char_pos = results.back();
33     if (cid_font)
34       text_char_pos.m_bFontStyle = true;
35     WideString unicode = font->UnicodeFromCharCode(char_code);
36     text_char_pos.m_Unicode = !unicode.IsEmpty() ? unicode[0] : char_code;
37     text_char_pos.m_GlyphIndex =
38         font->GlyphFromCharCode(char_code, &is_vertical_glyph);
39     uint32_t glyph_id = text_char_pos.m_GlyphIndex;
40 #if defined(OS_APPLE)
41     text_char_pos.m_ExtGID = font->GlyphFromCharCodeExt(char_code);
42     glyph_id = text_char_pos.m_ExtGID != static_cast<uint32_t>(-1)
43                    ? text_char_pos.m_ExtGID
44                    : text_char_pos.m_GlyphIndex;
45 #endif
46     bool is_invalid_glyph = glyph_id == static_cast<uint32_t>(-1);
47     bool is_true_type_zero_glyph = glyph_id == 0 && font->IsTrueTypeFont();
48     bool use_fallback_font = false;
49     if (is_invalid_glyph || is_true_type_zero_glyph) {
50       text_char_pos.m_FallbackFontPosition =
51           font->FallbackFontFromCharcode(char_code);
52       text_char_pos.m_GlyphIndex = font->FallbackGlyphFromCharcode(
53           text_char_pos.m_FallbackFontPosition, char_code);
54       if (is_true_type_zero_glyph &&
55           text_char_pos.m_GlyphIndex == static_cast<uint32_t>(-1)) {
56         // For a TrueType font character, when finding the glyph from the
57         // fallback font fails, switch back to using the original font.
58 
59         // When keyword "ToUnicode" exists in the PDF file, it indicates
60         // a "ToUnicode" mapping file is used to convert from CIDs (which
61         // begins at decimal 0) to Unicode code. (See ToUnicode Mapping File
62         // Tutorial - Adobe
63         // https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/5411.ToUnicode.pdf
64         // and
65         // https://www.freetype.org/freetype2/docs/tutorial/step1.html#section-6)
66         if (has_to_unicode)
67           text_char_pos.m_GlyphIndex = 0;
68       } else {
69         use_fallback_font = true;
70       }
71     }
72     CFX_Font* current_font;
73     if (use_fallback_font) {
74       current_font =
75           font->GetFontFallback(text_char_pos.m_FallbackFontPosition);
76 #if defined(OS_APPLE)
77       text_char_pos.m_ExtGID = text_char_pos.m_GlyphIndex;
78 #endif
79     } else {
80       current_font = font->GetFont();
81       text_char_pos.m_FallbackFontPosition = -1;
82     }
83 
84     if (!font->IsEmbedded() && !font->IsCIDFont())
85       text_char_pos.m_FontCharWidth = font->GetCharWidthF(char_code);
86     else
87       text_char_pos.m_FontCharWidth = 0;
88 
89     text_char_pos.m_Origin = CFX_PointF(i > 0 ? char_pos[i - 1] : 0, 0);
90     text_char_pos.m_bGlyphAdjust = false;
91 
92     float scaling_factor = 1.0f;
93     if (!font->IsEmbedded() && font->HasFontWidths() && !is_vertical_writing &&
94         !current_font->GetSubstFont()->m_bFlagMM) {
95       int pdf_glyph_width = font->GetCharWidthF(char_code);
96       int font_glyph_width =
97           current_font ? current_font->GetGlyphWidth(text_char_pos.m_GlyphIndex)
98                        : 0;
99       if (font_glyph_width && pdf_glyph_width > font_glyph_width + 1) {
100         // Move the initial x position by half of the excess (transformed to
101         // text space coordinates).
102         text_char_pos.m_Origin.x +=
103             (pdf_glyph_width - font_glyph_width) * font_size / 2000.0f;
104       } else if (pdf_glyph_width && font_glyph_width &&
105                  pdf_glyph_width < font_glyph_width) {
106         scaling_factor = static_cast<float>(pdf_glyph_width) / font_glyph_width;
107         text_char_pos.m_AdjustMatrix[0] = scaling_factor;
108         text_char_pos.m_AdjustMatrix[1] = 0.0f;
109         text_char_pos.m_AdjustMatrix[2] = 0.0f;
110         text_char_pos.m_AdjustMatrix[3] = 1.0f;
111         text_char_pos.m_bGlyphAdjust = true;
112       }
113     }
114     if (!cid_font)
115       continue;
116 
117     uint16_t cid = cid_font->CIDFromCharCode(char_code);
118     if (is_vertical_writing) {
119       text_char_pos.m_Origin = CFX_PointF(0, text_char_pos.m_Origin.x);
120 
121       CFX_Point16 vertical_origin = cid_font->GetVertOrigin(cid);
122       text_char_pos.m_Origin.x -= font_size * vertical_origin.x / 1000;
123       text_char_pos.m_Origin.y -= font_size * vertical_origin.y / 1000;
124     }
125 
126     const uint8_t* cid_transform = cid_font->GetCIDTransform(cid);
127     if (cid_transform && !is_vertical_glyph) {
128       text_char_pos.m_AdjustMatrix[0] =
129           cid_font->CIDTransformToFloat(cid_transform[0]) * scaling_factor;
130       text_char_pos.m_AdjustMatrix[1] =
131           cid_font->CIDTransformToFloat(cid_transform[1]) * scaling_factor;
132       text_char_pos.m_AdjustMatrix[2] =
133           cid_font->CIDTransformToFloat(cid_transform[2]);
134       text_char_pos.m_AdjustMatrix[3] =
135           cid_font->CIDTransformToFloat(cid_transform[3]);
136       text_char_pos.m_Origin.x +=
137           cid_font->CIDTransformToFloat(cid_transform[4]) * font_size;
138       text_char_pos.m_Origin.y +=
139           cid_font->CIDTransformToFloat(cid_transform[5]) * font_size;
140       text_char_pos.m_bGlyphAdjust = true;
141     }
142   }
143 
144   return results;
145 }
146