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