xref: /aosp_15_r20/external/pdfium/fxbarcode/oned/BC_OneDimWriter.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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