1 // Copyright 2014 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 // 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 "BC_OneDimWriter.h"
24 
25 #include <algorithm>
26 #include <memory>
27 
28 #include "xfa/src/fxbarcode/BC_Writer.h"
29 #include "xfa/src/fxbarcode/barcode.h"
30 #include "xfa/src/fxbarcode/common/BC_CommonBitMatrix.h"
31 
CBC_OneDimWriter()32 CBC_OneDimWriter::CBC_OneDimWriter() {
33   m_locTextLoc = BC_TEXT_LOC_BELOWEMBED;
34   m_bPrintChecksum = TRUE;
35   m_iDataLenth = 0;
36   m_bCalcChecksum = FALSE;
37   m_pFont = NULL;
38   m_fFontSize = 10;
39   ;
40   m_iFontStyle = 0;
41   m_fontColor = 0xff000000;
42   m_iContentLen = 0;
43   m_bLeftPadding = FALSE;
44   m_bRightPadding = FALSE;
45   m_output = NULL;
46 }
~CBC_OneDimWriter()47 CBC_OneDimWriter::~CBC_OneDimWriter() {
48   if (m_output != NULL) {
49     delete m_output;
50     m_output = NULL;
51   }
52 }
SetPrintChecksum(FX_BOOL checksum)53 void CBC_OneDimWriter::SetPrintChecksum(FX_BOOL checksum) {
54   m_bPrintChecksum = checksum;
55 }
SetDataLength(int32_t length)56 void CBC_OneDimWriter::SetDataLength(int32_t length) {
57   m_iDataLenth = length;
58 }
SetCalcChecksum(int32_t state)59 void CBC_OneDimWriter::SetCalcChecksum(int32_t state) {
60   m_bCalcChecksum = state;
61 }
SetFont(CFX_Font * cFont)62 FX_BOOL CBC_OneDimWriter::SetFont(CFX_Font* cFont) {
63   if (cFont == NULL) {
64     return FALSE;
65   }
66   m_pFont = cFont;
67   return TRUE;
68 }
SetFontSize(FX_FLOAT size)69 void CBC_OneDimWriter::SetFontSize(FX_FLOAT size) {
70   m_fFontSize = size;
71 }
SetFontStyle(int32_t style)72 void CBC_OneDimWriter::SetFontStyle(int32_t style) {
73   m_iFontStyle = style;
74 }
SetFontColor(FX_ARGB color)75 void CBC_OneDimWriter::SetFontColor(FX_ARGB color) {
76   m_fontColor = color;
77 }
Upper(FX_WCHAR ch)78 FX_WCHAR CBC_OneDimWriter::Upper(FX_WCHAR ch) {
79   if (ch >= 'a' && ch <= 'z') {
80     ch = ch - ('a' - 'A');
81   }
82   return ch;
83 }
Encode(const CFX_ByteString & contents,BCFORMAT format,int32_t & outWidth,int32_t & outHeight,int32_t hints,int32_t & e)84 uint8_t* CBC_OneDimWriter::Encode(const CFX_ByteString& contents,
85                                   BCFORMAT format,
86                                   int32_t& outWidth,
87                                   int32_t& outHeight,
88                                   int32_t hints,
89                                   int32_t& e) {
90   uint8_t* ret = NULL;
91   outHeight = 1;
92   if (m_Width >= 20) {
93     ret = Encode(contents, outWidth, e);
94   } else {
95     ret = Encode(contents, outWidth, e);
96   }
97   BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
98   return ret;
99 }
Encode(const CFX_ByteString & contents,BCFORMAT format,int32_t & outWidth,int32_t & outHeight,int32_t & e)100 uint8_t* CBC_OneDimWriter::Encode(const CFX_ByteString& contents,
101                                   BCFORMAT format,
102                                   int32_t& outWidth,
103                                   int32_t& outHeight,
104                                   int32_t& e) {
105   uint8_t* ret = Encode(contents, format, outWidth, outHeight, 0, e);
106   BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
107   return ret;
108 }
AppendPattern(uint8_t * target,int32_t pos,const int32_t * pattern,int32_t patternLength,int32_t startColor,int32_t & e)109 int32_t CBC_OneDimWriter::AppendPattern(uint8_t* target,
110                                         int32_t pos,
111                                         const int32_t* pattern,
112                                         int32_t patternLength,
113                                         int32_t startColor,
114                                         int32_t& e) {
115   if (startColor != 0 && startColor != 1) {
116     e = BCExceptionValueMustBeEither0or1;
117     return 0;
118   }
119   uint8_t color = (uint8_t)startColor;
120   int32_t numAdded = 0;
121   for (int32_t i = 0; i < patternLength; i++) {
122     for (int32_t j = 0; j < pattern[i]; j++) {
123       target[pos] = color;
124       pos += 1;
125       numAdded += 1;
126     }
127     color ^= 1;
128   }
129   return numAdded;
130 }
CalcTextInfo(const CFX_ByteString & text,FXTEXT_CHARPOS * charPos,CFX_Font * cFont,FX_FLOAT geWidth,int32_t fontSize,FX_FLOAT & charsLen)131 void CBC_OneDimWriter::CalcTextInfo(const CFX_ByteString& text,
132                                     FXTEXT_CHARPOS* charPos,
133                                     CFX_Font* cFont,
134                                     FX_FLOAT geWidth,
135                                     int32_t fontSize,
136                                     FX_FLOAT& charsLen) {
137   std::unique_ptr<CFX_UnicodeEncodingEx> encoding(
138       FX_CreateFontEncodingEx(cFont));
139 
140   int32_t length = text.GetLength();
141   FX_DWORD* pCharCode = FX_Alloc(FX_DWORD, text.GetLength());
142   FX_FLOAT charWidth = 0;
143   for (int32_t j = 0; j < text.GetLength(); j++) {
144     pCharCode[j] = encoding->CharCodeFromUnicode(text[j]);
145     int32_t glyp_code = encoding->GlyphFromCharCode(pCharCode[j]);
146     int32_t glyp_value = cFont->GetGlyphWidth(glyp_code);
147     FX_FLOAT temp = (FX_FLOAT)((glyp_value)*fontSize / 1000.0);
148     charWidth += temp;
149   }
150   charsLen = charWidth;
151   FX_FLOAT leftPositon = (FX_FLOAT)(geWidth - charsLen) / 2.0f;
152   if (leftPositon < 0 && geWidth == 0) {
153     leftPositon = 0;
154   }
155   FX_FLOAT penX = 0.0;
156   FX_FLOAT penY =
157       (FX_FLOAT)FXSYS_abs(cFont->GetDescent()) * (FX_FLOAT)fontSize / 1000.0f;
158   FX_FLOAT left = leftPositon;
159   FX_FLOAT top = 0.0;
160   charPos[0].m_OriginX = penX + left;
161   charPos[0].m_OriginY = penY + top;
162   charPos[0].m_GlyphIndex = encoding->GlyphFromCharCode(pCharCode[0]);
163   charPos[0].m_FontCharWidth = cFont->GetGlyphWidth(charPos[0].m_GlyphIndex);
164 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
165   charPos[0].m_ExtGID = charPos[0].m_GlyphIndex;
166 #endif
167   penX += (FX_FLOAT)(charPos[0].m_FontCharWidth) * (FX_FLOAT)fontSize / 1000.0f;
168   for (int32_t i = 1; i < length; i++) {
169     charPos[i].m_OriginX = penX + left;
170     charPos[i].m_OriginY = penY + top;
171     charPos[i].m_GlyphIndex = encoding->GlyphFromCharCode(pCharCode[i]);
172     charPos[i].m_FontCharWidth = cFont->GetGlyphWidth(charPos[i].m_GlyphIndex);
173 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
174     charPos[i].m_ExtGID = charPos[i].m_GlyphIndex;
175 #endif
176     penX +=
177         (FX_FLOAT)(charPos[i].m_FontCharWidth) * (FX_FLOAT)fontSize / 1000.0f;
178   }
179   FX_Free(pCharCode);
180 }
ShowDeviceChars(CFX_RenderDevice * device,const CFX_Matrix * matrix,const CFX_ByteString str,FX_FLOAT geWidth,FXTEXT_CHARPOS * pCharPos,FX_FLOAT locX,FX_FLOAT locY,int32_t barWidth)181 void CBC_OneDimWriter::ShowDeviceChars(CFX_RenderDevice* device,
182                                        const CFX_Matrix* matrix,
183                                        const CFX_ByteString str,
184                                        FX_FLOAT geWidth,
185                                        FXTEXT_CHARPOS* pCharPos,
186                                        FX_FLOAT locX,
187                                        FX_FLOAT locY,
188                                        int32_t barWidth) {
189   int32_t iFontSize = (int32_t)fabs(m_fFontSize);
190   int32_t iTextHeight = iFontSize + 1;
191   CFX_FloatRect rect((FX_FLOAT)locX, (FX_FLOAT)locY, (FX_FLOAT)(locX + geWidth),
192                      (FX_FLOAT)(locY + iTextHeight));
193   if (geWidth != m_Width) {
194     rect.right -= 1;
195   }
196   matrix->TransformRect(rect);
197   FX_RECT re = rect.GetOutterRect();
198   device->FillRect(&re, m_backgroundColor);
199   CFX_Matrix affine_matrix(1.0, 0.0, 0.0, -1.0, (FX_FLOAT)locX,
200                            (FX_FLOAT)(locY + iFontSize));
201   if (matrix != NULL) {
202     affine_matrix.Concat(*matrix);
203   }
204   device->DrawNormalText(str.GetLength(), pCharPos, m_pFont,
205                          CFX_GEModule::Get()->GetFontCache(),
206                          (FX_FLOAT)iFontSize, (CFX_Matrix*)&affine_matrix,
207                          m_fontColor, FXTEXT_CLEARTYPE);
208 }
ShowBitmapChars(CFX_DIBitmap * pOutBitmap,const CFX_ByteString str,FX_FLOAT geWidth,FXTEXT_CHARPOS * pCharPos,FX_FLOAT locX,FX_FLOAT locY,int32_t barWidth)209 void CBC_OneDimWriter::ShowBitmapChars(CFX_DIBitmap* pOutBitmap,
210                                        const CFX_ByteString str,
211                                        FX_FLOAT geWidth,
212                                        FXTEXT_CHARPOS* pCharPos,
213                                        FX_FLOAT locX,
214                                        FX_FLOAT locY,
215                                        int32_t barWidth) {
216   int32_t iFontSize = (int32_t)fabs(m_fFontSize);
217   int32_t iTextHeight = iFontSize + 1;
218   CFX_FxgeDevice ge;
219   ge.Create((int)geWidth, iTextHeight, m_colorSpace);
220   FX_RECT geRect(0, 0, (int)geWidth, iTextHeight);
221   ge.FillRect(&geRect, m_backgroundColor);
222   CFX_Matrix affine_matrix(1.0, 0.0, 0.0, -1.0, 0.0, (FX_FLOAT)iFontSize);
223   ge.DrawNormalText(str.GetLength(), pCharPos, m_pFont,
224                     CFX_GEModule::Get()->GetFontCache(), (FX_FLOAT)iFontSize,
225                     (CFX_Matrix*)&affine_matrix, m_fontColor, FXTEXT_CLEARTYPE);
226   CFX_FxgeDevice geBitmap;
227   geBitmap.Attach(pOutBitmap);
228   geBitmap.SetDIBits(ge.GetBitmap(), (int)locX, (int)locY);
229 }
ShowChars(const CFX_WideStringC & contents,CFX_DIBitmap * pOutBitmap,CFX_RenderDevice * device,const CFX_Matrix * matrix,int32_t barWidth,int32_t multiple,int32_t & e)230 void CBC_OneDimWriter::ShowChars(const CFX_WideStringC& contents,
231                                  CFX_DIBitmap* pOutBitmap,
232                                  CFX_RenderDevice* device,
233                                  const CFX_Matrix* matrix,
234                                  int32_t barWidth,
235                                  int32_t multiple,
236                                  int32_t& e) {
237   if (device == NULL && pOutBitmap == NULL) {
238     e = BCExceptionIllegalArgument;
239     return;
240   }
241   if (m_pFont == NULL) {
242     e = BCExceptionNullPointer;
243     return;
244   }
245   CFX_ByteString str = FX_UTF8Encode(contents);
246   int32_t iLen = str.GetLength();
247   FXTEXT_CHARPOS* pCharPos = FX_Alloc(FXTEXT_CHARPOS, iLen);
248   FXSYS_memset(pCharPos, 0, sizeof(FXTEXT_CHARPOS) * iLen);
249   FX_FLOAT charsLen = 0;
250   FX_FLOAT geWidth = 0;
251   if (m_locTextLoc == BC_TEXT_LOC_ABOVEEMBED ||
252       m_locTextLoc == BC_TEXT_LOC_BELOWEMBED) {
253     geWidth = 0;
254   } else if (m_locTextLoc == BC_TEXT_LOC_ABOVE ||
255              m_locTextLoc == BC_TEXT_LOC_BELOW) {
256     geWidth = (FX_FLOAT)barWidth;
257   }
258   int32_t iFontSize = (int32_t)fabs(m_fFontSize);
259   int32_t iTextHeight = iFontSize + 1;
260   CalcTextInfo(str, pCharPos, m_pFont, geWidth, iFontSize, charsLen);
261   if (charsLen < 1) {
262     return;
263   }
264   int32_t locX = 0;
265   int32_t locY = 0;
266   switch (m_locTextLoc) {
267     case BC_TEXT_LOC_ABOVEEMBED:
268       locX = (int32_t)(barWidth - charsLen) / 2;
269       locY = 0;
270       geWidth = charsLen;
271       break;
272     case BC_TEXT_LOC_ABOVE:
273       locX = 0;
274       locY = 0;
275       geWidth = (FX_FLOAT)barWidth;
276       break;
277     case BC_TEXT_LOC_BELOWEMBED:
278       locX = (int32_t)(barWidth - charsLen) / 2;
279       locY = m_Height - iTextHeight;
280       geWidth = charsLen;
281       break;
282     case BC_TEXT_LOC_BELOW:
283     default:
284       locX = 0;
285       locY = m_Height - iTextHeight;
286       geWidth = (FX_FLOAT)barWidth;
287       break;
288   }
289   if (device != NULL) {
290     ShowDeviceChars(device, matrix, str, geWidth, pCharPos, (FX_FLOAT)locX,
291                     (FX_FLOAT)locY, barWidth);
292   } else {
293     ShowBitmapChars(pOutBitmap, str, geWidth, pCharPos, (FX_FLOAT)locX,
294                     (FX_FLOAT)locY, barWidth);
295   }
296   FX_Free(pCharPos);
297 }
RenderBitmapResult(CFX_DIBitmap * & pOutBitmap,const CFX_WideStringC & contents,int32_t & e)298 void CBC_OneDimWriter::RenderBitmapResult(CFX_DIBitmap*& pOutBitmap,
299                                           const CFX_WideStringC& contents,
300                                           int32_t& e) {
301   if (m_output == NULL) {
302     BC_EXCEPTION_CHECK_ReturnVoid(e);
303   }
304   pOutBitmap = CreateDIBitmap(m_output->GetWidth(), m_output->GetHeight());
305   pOutBitmap->Clear(m_backgroundColor);
306   if (!pOutBitmap) {
307     e = BCExceptionFailToCreateBitmap;
308     return;
309   }
310   for (int32_t x = 0; x < m_output->GetWidth(); x++) {
311     for (int32_t y = 0; y < m_output->GetHeight(); y++) {
312       if (m_output->Get(x, y)) {
313         pOutBitmap->SetPixel(x, y, m_barColor);
314       }
315     }
316   }
317   int32_t i = 0;
318   for (; i < contents.GetLength(); i++)
319     if (contents.GetAt(i) != ' ') {
320       break;
321     }
322   if (m_locTextLoc != BC_TEXT_LOC_NONE && i < contents.GetLength()) {
323     ShowChars(contents, pOutBitmap, NULL, NULL, m_barWidth, m_multiple, e);
324     BC_EXCEPTION_CHECK_ReturnVoid(e);
325   }
326   CFX_DIBitmap* pStretchBitmap = pOutBitmap->StretchTo(m_Width, m_Height);
327   if (pOutBitmap) {
328     delete pOutBitmap;
329   }
330   pOutBitmap = pStretchBitmap;
331 }
RenderDeviceResult(CFX_RenderDevice * device,const CFX_Matrix * matrix,const CFX_WideStringC & contents,int32_t & e)332 void CBC_OneDimWriter::RenderDeviceResult(CFX_RenderDevice* device,
333                                           const CFX_Matrix* matrix,
334                                           const CFX_WideStringC& contents,
335                                           int32_t& e) {
336   if (m_output == NULL) {
337     BC_EXCEPTION_CHECK_ReturnVoid(e);
338   }
339   CFX_GraphStateData stateData;
340   CFX_PathData path;
341   path.AppendRect(0, 0, (FX_FLOAT)m_Width, (FX_FLOAT)m_Height);
342   device->DrawPath(&path, matrix, &stateData, m_backgroundColor,
343                    m_backgroundColor, FXFILL_ALTERNATE);
344   CFX_Matrix matri(m_outputHScale, 0.0, 0.0, (FX_FLOAT)m_Height, 0.0, 0.0);
345   matri.Concat(*matrix);
346   for (int32_t x = 0; x < m_output->GetWidth(); x++) {
347     for (int32_t y = 0; y < m_output->GetHeight(); y++) {
348       CFX_PathData rect;
349       rect.AppendRect((FX_FLOAT)x, (FX_FLOAT)y, (FX_FLOAT)(x + 1),
350                       (FX_FLOAT)(y + 1));
351       CFX_GraphStateData stateData;
352       if (m_output->Get(x, y)) {
353         device->DrawPath(&rect, &matri, &stateData, m_barColor, 0,
354                          FXFILL_WINDING);
355       }
356     }
357   }
358   int32_t i = 0;
359   for (; i < contents.GetLength(); i++)
360     if (contents.GetAt(i) != ' ') {
361       break;
362     }
363   if (m_locTextLoc != BC_TEXT_LOC_NONE && i < contents.GetLength()) {
364     ShowChars(contents, NULL, device, matrix, m_barWidth, m_multiple, e);
365     BC_EXCEPTION_CHECK_ReturnVoid(e);
366   }
367 }
RenderResult(const CFX_WideStringC & contents,uint8_t * code,int32_t codeLength,FX_BOOL isDevice,int32_t & e)368 void CBC_OneDimWriter::RenderResult(const CFX_WideStringC& contents,
369                                     uint8_t* code,
370                                     int32_t codeLength,
371                                     FX_BOOL isDevice,
372                                     int32_t& e) {
373   if (codeLength < 1) {
374     BC_EXCEPTION_CHECK_ReturnVoid(e);
375   }
376   if (m_ModuleHeight < 20.0) {
377     m_ModuleHeight = 20;
378   }
379   int32_t codeOldLength = codeLength;
380   int32_t leftPadding = 0;
381   int32_t rightPadding = 0;
382   if (m_bLeftPadding) {
383     leftPadding = 7;
384   }
385   if (m_bRightPadding) {
386     rightPadding = 7;
387   }
388   codeLength += leftPadding;
389   codeLength += rightPadding;
390   m_outputHScale = 1.0;
391   if (m_Width > 0) {
392     m_outputHScale = (FX_FLOAT)m_Width / (FX_FLOAT)codeLength;
393   }
394   if (!isDevice) {
395     m_outputHScale =
396         std::max(m_outputHScale, static_cast<FX_FLOAT>(m_ModuleWidth));
397   }
398   FX_FLOAT dataLengthScale = 1.0;
399   if (m_iDataLenth > 0 && contents.GetLength() != 0) {
400     dataLengthScale = FX_FLOAT(contents.GetLength()) / FX_FLOAT(m_iDataLenth);
401   }
402   if (m_iDataLenth > 0 && contents.GetLength() == 0) {
403     dataLengthScale = FX_FLOAT(1) / FX_FLOAT(m_iDataLenth);
404   }
405   m_multiple = 1;
406   if (!isDevice) {
407     m_multiple = (int32_t)ceil(m_outputHScale * dataLengthScale);
408   }
409   int32_t outputHeight = 1;
410   if (!isDevice) {
411     if (m_Height == 0) {
412       outputHeight = std::max(20, m_ModuleHeight);
413     } else {
414       outputHeight = m_Height;
415     }
416   }
417   int32_t outputWidth = codeLength;
418   if (!isDevice) {
419     outputWidth = (int32_t)(codeLength * m_multiple / dataLengthScale);
420   }
421   m_barWidth = m_Width;
422   if (!isDevice) {
423     m_barWidth = codeLength * m_multiple;
424   }
425   m_output = new CBC_CommonBitMatrix;
426   m_output->Init(outputWidth, outputHeight);
427   int32_t outputX = leftPadding * m_multiple;
428   for (int32_t inputX = 0; inputX < codeOldLength; inputX++) {
429     if (code[inputX] == 1) {
430       if (outputX >= outputWidth) {
431         break;
432       }
433       if (outputX + m_multiple > outputWidth && outputWidth - outputX > 0) {
434         m_output->SetRegion(outputX, 0, outputWidth - outputX, outputHeight, e);
435         break;
436       }
437       m_output->SetRegion(outputX, 0, m_multiple, outputHeight, e);
438       BC_EXCEPTION_CHECK_ReturnVoid(e);
439     }
440     outputX += m_multiple;
441   }
442 }
443