1 // Copyright 2014 The PDFium Authors
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 // Original code is licensed as follows:
7 /*
8 * Copyright 2011 ZXing authors
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22
23 #include "fxbarcode/oned/BC_OneDimWriter.h"
24
25 #include <math.h>
26
27 #include <algorithm>
28 #include <memory>
29 #include <vector>
30
31 #include "build/build_config.h"
32 #include "core/fxge/cfx_defaultrenderdevice.h"
33 #include "core/fxge/cfx_fillrenderoptions.h"
34 #include "core/fxge/cfx_font.h"
35 #include "core/fxge/cfx_graphstatedata.h"
36 #include "core/fxge/cfx_path.h"
37 #include "core/fxge/cfx_renderdevice.h"
38 #include "core/fxge/cfx_unicodeencodingex.h"
39 #include "core/fxge/text_char_pos.h"
40 #include "fxbarcode/BC_Writer.h"
41
42 // static
HasValidContentSize(WideStringView contents)43 bool CBC_OneDimWriter::HasValidContentSize(WideStringView contents) {
44 // Limit the size of 1D barcodes. Typical 1D barcodes are short so this should
45 // be sufficient for most use cases.
46 static constexpr size_t kMaxInputLengthBytes = 8192;
47
48 size_t size = contents.GetLength();
49 return size > 0 && size <= kMaxInputLengthBytes;
50 }
51
52 CBC_OneDimWriter::CBC_OneDimWriter() = default;
53
54 CBC_OneDimWriter::~CBC_OneDimWriter() = default;
55
SetPrintChecksum(bool checksum)56 void CBC_OneDimWriter::SetPrintChecksum(bool checksum) {
57 m_bPrintChecksum = checksum;
58 }
59
SetDataLength(int32_t length)60 void CBC_OneDimWriter::SetDataLength(int32_t length) {
61 m_iDataLenth = length;
62 }
63
SetCalcChecksum(bool state)64 void CBC_OneDimWriter::SetCalcChecksum(bool state) {
65 m_bCalcChecksum = state;
66 }
67
SetFont(CFX_Font * cFont)68 bool CBC_OneDimWriter::SetFont(CFX_Font* cFont) {
69 if (!cFont)
70 return false;
71
72 m_pFont = cFont;
73 return true;
74 }
75
SetFontSize(float size)76 void CBC_OneDimWriter::SetFontSize(float size) {
77 m_fFontSize = size;
78 }
79
SetFontStyle(int32_t style)80 void CBC_OneDimWriter::SetFontStyle(int32_t style) {
81 m_iFontStyle = style;
82 }
83
SetFontColor(FX_ARGB color)84 void CBC_OneDimWriter::SetFontColor(FX_ARGB color) {
85 m_fontColor = color;
86 }
87
AppendPattern(pdfium::span<uint8_t> target,pdfium::span<const uint8_t> pattern,bool startColor)88 pdfium::span<uint8_t> CBC_OneDimWriter::AppendPattern(
89 pdfium::span<uint8_t> target,
90 pdfium::span<const uint8_t> pattern,
91 bool startColor) {
92 bool color = startColor;
93 size_t added = 0;
94 size_t pos = 0;
95 for (const int8_t pattern_value : pattern) {
96 for (int32_t i = 0; i < pattern_value; ++i)
97 target[pos++] = color ? 1 : 0;
98 added += pattern_value;
99 color = !color;
100 }
101 return target.subspan(added);
102 }
103
CalcTextInfo(const ByteString & text,TextCharPos * charPos,CFX_Font * cFont,float geWidth,int32_t fontSize,float & charsLen)104 void CBC_OneDimWriter::CalcTextInfo(const ByteString& text,
105 TextCharPos* charPos,
106 CFX_Font* cFont,
107 float geWidth,
108 int32_t fontSize,
109 float& charsLen) {
110 std::unique_ptr<CFX_UnicodeEncodingEx> encoding =
111 FX_CreateFontEncodingEx(cFont);
112
113 const size_t length = text.GetLength();
114 std::vector<uint32_t> charcodes(length);
115 float charWidth = 0;
116 for (size_t i = 0; i < length; ++i) {
117 charcodes[i] = encoding->CharCodeFromUnicode(text[i]);
118 int32_t glyph_code = encoding->GlyphFromCharCode(charcodes[i]);
119 int glyph_value = cFont->GetGlyphWidth(glyph_code);
120 float temp = glyph_value * fontSize / 1000.0;
121 charWidth += temp;
122 }
123 charsLen = charWidth;
124 float leftPositon = (float)(geWidth - charsLen) / 2.0f;
125 if (leftPositon < 0 && geWidth == 0) {
126 leftPositon = 0;
127 }
128 float penX = 0.0;
129 float penY = (float)abs(cFont->GetDescent()) * (float)fontSize / 1000.0f;
130 float left = leftPositon;
131 float top = 0.0;
132 charPos[0].m_Origin = CFX_PointF(penX + left, penY + top);
133 charPos[0].m_GlyphIndex = encoding->GlyphFromCharCode(charcodes[0]);
134 charPos[0].m_FontCharWidth = cFont->GetGlyphWidth(charPos[0].m_GlyphIndex);
135 #if BUILDFLAG(IS_APPLE)
136 charPos[0].m_ExtGID = charPos[0].m_GlyphIndex;
137 #endif
138 penX += (float)(charPos[0].m_FontCharWidth) * (float)fontSize / 1000.0f;
139 for (size_t i = 1; i < length; i++) {
140 charPos[i].m_Origin = CFX_PointF(penX + left, penY + top);
141 charPos[i].m_GlyphIndex = encoding->GlyphFromCharCode(charcodes[i]);
142 charPos[i].m_FontCharWidth = cFont->GetGlyphWidth(charPos[i].m_GlyphIndex);
143 #if BUILDFLAG(IS_APPLE)
144 charPos[i].m_ExtGID = charPos[i].m_GlyphIndex;
145 #endif
146 penX += (float)(charPos[i].m_FontCharWidth) * (float)fontSize / 1000.0f;
147 }
148 }
149
ShowDeviceChars(CFX_RenderDevice * device,const CFX_Matrix & matrix,const ByteString str,float geWidth,TextCharPos * pCharPos,float locX,float locY,int32_t barWidth)150 void CBC_OneDimWriter::ShowDeviceChars(CFX_RenderDevice* device,
151 const CFX_Matrix& matrix,
152 const ByteString str,
153 float geWidth,
154 TextCharPos* pCharPos,
155 float locX,
156 float locY,
157 int32_t barWidth) {
158 int32_t iFontSize = static_cast<int32_t>(fabs(m_fFontSize));
159 int32_t iTextHeight = iFontSize + 1;
160 CFX_FloatRect rect((float)locX, (float)locY, (float)(locX + geWidth),
161 (float)(locY + iTextHeight));
162 if (geWidth != m_Width) {
163 rect.right -= 1;
164 }
165 FX_RECT re = matrix.TransformRect(rect).GetOuterRect();
166 device->FillRect(re, kBackgroundColor);
167 CFX_Matrix affine_matrix(1.0, 0.0, 0.0, -1.0, (float)locX,
168 (float)(locY + iFontSize));
169 affine_matrix.Concat(matrix);
170 device->DrawNormalText(pdfium::make_span(pCharPos, str.GetLength()), m_pFont,
171 static_cast<float>(iFontSize), affine_matrix,
172 m_fontColor, GetTextRenderOptions());
173 }
174
ShowChars(WideStringView contents,CFX_RenderDevice * device,const CFX_Matrix & matrix,int32_t barWidth)175 bool CBC_OneDimWriter::ShowChars(WideStringView contents,
176 CFX_RenderDevice* device,
177 const CFX_Matrix& matrix,
178 int32_t barWidth) {
179 if (!device || !m_pFont)
180 return false;
181
182 ByteString str = FX_UTF8Encode(contents);
183 std::vector<TextCharPos> charpos(str.GetLength());
184 float charsLen = 0;
185 float geWidth = 0;
186 if (m_locTextLoc == BC_TEXT_LOC::kAboveEmbed ||
187 m_locTextLoc == BC_TEXT_LOC::kBelowEmbed) {
188 geWidth = 0;
189 } else if (m_locTextLoc == BC_TEXT_LOC::kAbove ||
190 m_locTextLoc == BC_TEXT_LOC::kBelow) {
191 geWidth = (float)barWidth;
192 }
193 int32_t iFontSize = static_cast<int32_t>(fabs(m_fFontSize));
194 int32_t iTextHeight = iFontSize + 1;
195 CalcTextInfo(str, charpos.data(), m_pFont, geWidth, iFontSize, charsLen);
196 if (charsLen < 1)
197 return true;
198
199 int32_t locX = 0;
200 int32_t locY = 0;
201 switch (m_locTextLoc) {
202 case BC_TEXT_LOC::kAboveEmbed:
203 locX = static_cast<int32_t>(barWidth - charsLen) / 2;
204 locY = 0;
205 geWidth = charsLen;
206 break;
207 case BC_TEXT_LOC::kAbove:
208 locX = 0;
209 locY = 0;
210 geWidth = (float)barWidth;
211 break;
212 case BC_TEXT_LOC::kBelowEmbed:
213 locX = static_cast<int32_t>(barWidth - charsLen) / 2;
214 locY = m_Height - iTextHeight;
215 geWidth = charsLen;
216 break;
217 case BC_TEXT_LOC::kBelow:
218 default:
219 locX = 0;
220 locY = m_Height - iTextHeight;
221 geWidth = (float)barWidth;
222 break;
223 }
224 ShowDeviceChars(device, matrix, str, geWidth, charpos.data(), (float)locX,
225 (float)locY, barWidth);
226 return true;
227 }
228
RenderDeviceResult(CFX_RenderDevice * device,const CFX_Matrix & matrix,WideStringView contents)229 bool CBC_OneDimWriter::RenderDeviceResult(CFX_RenderDevice* device,
230 const CFX_Matrix& matrix,
231 WideStringView contents) {
232 if (m_output.empty())
233 return false;
234
235 CFX_GraphStateData stateData;
236 CFX_Path path;
237 path.AppendRect(0, 0, static_cast<float>(m_Width),
238 static_cast<float>(m_Height));
239 device->DrawPath(path, &matrix, &stateData, kBackgroundColor,
240 kBackgroundColor, CFX_FillRenderOptions::EvenOddOptions());
241 CFX_Matrix scaledMatrix(m_outputHScale, 0.0, 0.0,
242 static_cast<float>(m_Height), 0.0, 0.0);
243 scaledMatrix.Concat(matrix);
244 for (const auto& rect : m_output) {
245 CFX_GraphStateData data;
246 device->DrawPath(rect, &scaledMatrix, &data, kBarColor, 0,
247 CFX_FillRenderOptions::WindingOptions());
248 }
249
250 return m_locTextLoc == BC_TEXT_LOC::kNone || !contents.Contains(' ') ||
251 ShowChars(contents, device, matrix, m_barWidth);
252 }
253
RenderResult(WideStringView contents,pdfium::span<const uint8_t> code)254 bool CBC_OneDimWriter::RenderResult(WideStringView contents,
255 pdfium::span<const uint8_t> code) {
256 if (code.empty())
257 return false;
258
259 m_ModuleHeight = std::max(m_ModuleHeight, 20);
260 const size_t original_codelength = code.size();
261 const int32_t leftPadding = m_bLeftPadding ? 7 : 0;
262 const int32_t rightPadding = m_bRightPadding ? 7 : 0;
263 const size_t codelength = code.size() + leftPadding + rightPadding;
264 m_outputHScale =
265 m_Width > 0 ? static_cast<float>(m_Width) / static_cast<float>(codelength)
266 : 1.0;
267 m_barWidth = m_Width;
268
269 m_output.clear();
270 m_output.reserve(original_codelength);
271 for (size_t i = 0; i < original_codelength; ++i) {
272 if (code[i] != 1)
273 continue;
274
275 size_t output_index = i + leftPadding;
276 if (output_index >= codelength)
277 return true;
278
279 m_output.emplace_back();
280 m_output.back().AppendRect(output_index, 0.0f, output_index + 1, 1.0f);
281 }
282 return true;
283 }
284