Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fxbarcode / src / BC_PDF417DetectionResult.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_PDF417Codeword.h"\r
9 #include "include/BC_PDF417BarcodeMetadata.h"\r
10 #include "include/BC_PDF417BoundingBox.h"\r
11 #include "include/BC_PDF417DetectionResultColumn.h"\r
12 #include "include/BC_PDF417Common.h"\r
13 #include "include/BC_PDF417DetectionResultRowIndicatorColumn.h"\r
14 #include "include/BC_PDF417DetectionResult.h"\r
15 FX_INT32 CBC_DetectionResult::ADJUST_ROW_NUMBER_SKIP = 2;\r
16 CBC_DetectionResult::CBC_DetectionResult(CBC_BarcodeMetadata* barcodeMetadata, CBC_BoundingBox* boundingBox)\r
17 {\r
18     m_barcodeMetadata = barcodeMetadata;\r
19     m_barcodeColumnCount = barcodeMetadata->getColumnCount();\r
20     m_boundingBox = boundingBox;\r
21     m_detectionResultColumns.SetSize(m_barcodeColumnCount + 2);\r
22     for (FX_INT32 i = 0; i < m_barcodeColumnCount + 2; i++) {\r
23         m_detectionResultColumns[i] = NULL;\r
24     }\r
25 }\r
26 CBC_DetectionResult::~CBC_DetectionResult()\r
27 {\r
28     delete m_boundingBox;\r
29     delete m_barcodeMetadata;\r
30     m_detectionResultColumns.RemoveAll();\r
31 }\r
32 CFX_PtrArray& CBC_DetectionResult::getDetectionResultColumns()\r
33 {\r
34     adjustIndicatorColumnRowNumbers((CBC_DetectionResultColumn*)m_detectionResultColumns.GetAt(0));\r
35     adjustIndicatorColumnRowNumbers((CBC_DetectionResultColumn*)m_detectionResultColumns.GetAt(m_barcodeColumnCount + 1));\r
36     FX_INT32 unadjustedCodewordCount = CBC_PDF417Common::MAX_CODEWORDS_IN_BARCODE;\r
37     FX_INT32 previousUnadjustedCount;\r
38     do {\r
39         previousUnadjustedCount = unadjustedCodewordCount;\r
40         unadjustedCodewordCount = adjustRowNumbers();\r
41     } while (unadjustedCodewordCount > 0 && unadjustedCodewordCount < previousUnadjustedCount);\r
42     return m_detectionResultColumns;\r
43 }\r
44 void CBC_DetectionResult::setBoundingBox(CBC_BoundingBox* boundingBox)\r
45 {\r
46     m_boundingBox = boundingBox;\r
47 }\r
48 CBC_BoundingBox* CBC_DetectionResult::getBoundingBox()\r
49 {\r
50     return m_boundingBox;\r
51 }\r
52 void CBC_DetectionResult::setDetectionResultColumn(FX_INT32 barcodeColumn, CBC_DetectionResultColumn* detectionResultColumn)\r
53 {\r
54     m_detectionResultColumns[barcodeColumn] = detectionResultColumn;\r
55 }\r
56 CBC_DetectionResultColumn* CBC_DetectionResult::getDetectionResultColumn(FX_INT32 barcodeColumn)\r
57 {\r
58     return (CBC_DetectionResultColumn*)m_detectionResultColumns[barcodeColumn];\r
59 }\r
60 CFX_ByteString CBC_DetectionResult::toString()\r
61 {\r
62     CBC_DetectionResultColumn* rowIndicatorColumn = (CBC_DetectionResultColumn*)m_detectionResultColumns[0];\r
63     if (rowIndicatorColumn == NULL) {\r
64         rowIndicatorColumn = (CBC_DetectionResultColumn*)m_detectionResultColumns[m_barcodeColumnCount + 1];\r
65     }\r
66     CFX_ByteString result;\r
67     for (FX_INT32 codewordsRow = 0; codewordsRow < rowIndicatorColumn->getCodewords()->GetSize(); codewordsRow++) {\r
68         result += (FX_CHAR) codewordsRow;\r
69         for (FX_INT32 barcodeColumn = 0; barcodeColumn < m_barcodeColumnCount + 2; barcodeColumn++) {\r
70             if (m_detectionResultColumns[barcodeColumn] == NULL) {\r
71                 result += "    |   ";\r
72                 continue;\r
73             }\r
74             CBC_Codeword* codeword = (CBC_Codeword*)((CBC_DetectionResultColumn*)m_detectionResultColumns[barcodeColumn])->getCodewords()->GetAt(codewordsRow);\r
75             if (codeword == NULL) {\r
76                 result += "    |   ";\r
77                 continue;\r
78             }\r
79             result += codeword->getRowNumber();\r
80             result += codeword->getValue();\r
81         }\r
82     }\r
83     return result;\r
84 }\r
85 void CBC_DetectionResult::adjustIndicatorColumnRowNumbers(CBC_DetectionResultColumn* detectionResultColumn)\r
86 {\r
87     if (detectionResultColumn != NULL) {\r
88         ((CBC_DetectionResultRowIndicatorColumn*)detectionResultColumn)->adjustCompleteIndicatorColumnRowNumbers(*m_barcodeMetadata);\r
89     }\r
90 }\r
91 FX_INT32 CBC_DetectionResult::adjustRowNumbers()\r
92 {\r
93     FX_INT32 unadjustedCount = adjustRowNumbersByRow();\r
94     if (unadjustedCount == 0) {\r
95         return 0;\r
96     }\r
97     for (FX_INT32 barcodeColumn = 1; barcodeColumn < m_barcodeColumnCount + 1; barcodeColumn++) {\r
98         CFX_PtrArray* codewords = ((CBC_DetectionResultColumn*)m_detectionResultColumns[barcodeColumn])->getCodewords();\r
99         for (FX_INT32 codewordsRow = 0; codewordsRow < codewords->GetSize(); codewordsRow++) {\r
100             if (codewords->GetAt(codewordsRow) == NULL) {\r
101                 continue;\r
102             }\r
103             if (!((CBC_Codeword*)codewords->GetAt(codewordsRow))->hasValidRowNumber()) {\r
104                 adjustRowNumbers(barcodeColumn, codewordsRow, codewords);\r
105             }\r
106         }\r
107     }\r
108     return unadjustedCount;\r
109 }\r
110 FX_INT32 CBC_DetectionResult::adjustRowNumbersByRow()\r
111 {\r
112     adjustRowNumbersFromBothRI();\r
113     FX_INT32 unadjustedCount = adjustRowNumbersFromLRI();\r
114     return unadjustedCount + adjustRowNumbersFromRRI();\r
115 }\r
116 FX_INT32 CBC_DetectionResult::adjustRowNumbersFromBothRI()\r
117 {\r
118     if (m_detectionResultColumns[0] == NULL || m_detectionResultColumns[m_barcodeColumnCount + 1] == NULL) {\r
119         return 0;\r
120     }\r
121     CFX_PtrArray* LRIcodewords = ((CBC_DetectionResultColumn*)m_detectionResultColumns[0])->getCodewords();\r
122     CFX_PtrArray* RRIcodewords = ((CBC_DetectionResultColumn*)m_detectionResultColumns[m_barcodeColumnCount + 1])->getCodewords();\r
123     for (FX_INT32 codewordsRow = 0; codewordsRow < LRIcodewords->GetSize(); codewordsRow++) {\r
124         if (LRIcodewords->GetAt(codewordsRow) != NULL &&\r
125                 RRIcodewords->GetAt(codewordsRow) != NULL &&\r
126                 ((CBC_Codeword*)LRIcodewords->GetAt(codewordsRow))->getRowNumber() == ((CBC_Codeword*)RRIcodewords->GetAt(codewordsRow))->getRowNumber()) {\r
127             for (FX_INT32 barcodeColumn = 1; barcodeColumn <= m_barcodeColumnCount; barcodeColumn++) {\r
128                 CBC_Codeword* codeword = (CBC_Codeword*)((CBC_DetectionResultColumn*)m_detectionResultColumns[barcodeColumn])->getCodewords()->GetAt(codewordsRow);\r
129                 if (codeword == NULL) {\r
130                     continue;\r
131                 }\r
132                 codeword->setRowNumber(((CBC_Codeword*)LRIcodewords->GetAt(codewordsRow))->getRowNumber());\r
133                 if (!codeword->hasValidRowNumber()) {\r
134                     ((CBC_DetectionResultColumn*)m_detectionResultColumns[barcodeColumn])->getCodewords()->SetAt(codewordsRow, NULL);\r
135                 }\r
136             }\r
137         }\r
138     }\r
139     return 0;\r
140 }\r
141 FX_INT32 CBC_DetectionResult::adjustRowNumbersFromRRI()\r
142 {\r
143     if (m_detectionResultColumns[m_barcodeColumnCount + 1] == NULL) {\r
144         return 0;\r
145     }\r
146     FX_INT32 unadjustedCount = 0;\r
147     CFX_PtrArray* codewords = ((CBC_DetectionResultColumn*) m_detectionResultColumns.GetAt(m_barcodeColumnCount + 1))->getCodewords();\r
148     for (FX_INT32 codewordsRow = 0; codewordsRow < codewords->GetSize(); codewordsRow++) {\r
149         if (codewords->GetAt(codewordsRow) == NULL) {\r
150             continue;\r
151         }\r
152         FX_INT32 rowIndicatorRowNumber = ((CBC_Codeword*)codewords->GetAt(codewordsRow))->getRowNumber();\r
153         FX_INT32 invalidRowCounts = 0;\r
154         for (FX_INT32 barcodeColumn = m_barcodeColumnCount + 1; barcodeColumn > 0 && invalidRowCounts < ADJUST_ROW_NUMBER_SKIP; barcodeColumn--) {\r
155             CBC_Codeword* codeword = (CBC_Codeword*)((CBC_DetectionResultColumn*)m_detectionResultColumns.GetAt(barcodeColumn))->getCodewords()->GetAt(codewordsRow);\r
156             if (codeword != NULL) {\r
157                 invalidRowCounts = adjustRowNumberIfValid(rowIndicatorRowNumber, invalidRowCounts, codeword);\r
158                 if (!codeword->hasValidRowNumber()) {\r
159                     unadjustedCount++;\r
160                 }\r
161             }\r
162         }\r
163     }\r
164     return unadjustedCount;\r
165 }\r
166 FX_INT32 CBC_DetectionResult::adjustRowNumbersFromLRI()\r
167 {\r
168     if (m_detectionResultColumns[0] == NULL) {\r
169         return 0;\r
170     }\r
171     FX_INT32 unadjustedCount = 0;\r
172     CFX_PtrArray* codewords = ((CBC_DetectionResultColumn*)m_detectionResultColumns.GetAt(0))->getCodewords();\r
173     for (FX_INT32 codewordsRow = 0; codewordsRow < codewords->GetSize(); codewordsRow++) {\r
174         if (codewords->GetAt(codewordsRow) == NULL) {\r
175             continue;\r
176         }\r
177         FX_INT32 rowIndicatorRowNumber = ((CBC_Codeword*)codewords->GetAt(codewordsRow))->getRowNumber();\r
178         FX_INT32 invalidRowCounts = 0;\r
179         for (FX_INT32 barcodeColumn = 1; barcodeColumn < m_barcodeColumnCount + 1 && invalidRowCounts < ADJUST_ROW_NUMBER_SKIP; barcodeColumn++) {\r
180             CBC_Codeword* codeword = (CBC_Codeword*)((CBC_DetectionResultColumn*)m_detectionResultColumns[barcodeColumn])->getCodewords()->GetAt(codewordsRow);\r
181             if (codeword != NULL) {\r
182                 invalidRowCounts = adjustRowNumberIfValid(rowIndicatorRowNumber, invalidRowCounts, codeword);\r
183                 if (!codeword->hasValidRowNumber()) {\r
184                     unadjustedCount++;\r
185                 }\r
186             }\r
187         }\r
188     }\r
189     return unadjustedCount;\r
190 }\r
191 FX_INT32 CBC_DetectionResult::adjustRowNumberIfValid(FX_INT32 rowIndicatorRowNumber, FX_INT32 invalidRowCounts, CBC_Codeword* codeword)\r
192 {\r
193     if (codeword == NULL) {\r
194         return invalidRowCounts;\r
195     }\r
196     if (!codeword->hasValidRowNumber()) {\r
197         if (codeword->isValidRowNumber(rowIndicatorRowNumber)) {\r
198             codeword->setRowNumber(rowIndicatorRowNumber);\r
199             invalidRowCounts = 0;\r
200         } else {\r
201             ++invalidRowCounts;\r
202         }\r
203     }\r
204     return invalidRowCounts;\r
205 }\r
206 void CBC_DetectionResult::adjustRowNumbers(FX_INT32 barcodeColumn, FX_INT32 codewordsRow, CFX_PtrArray* codewords)\r
207 {\r
208     CBC_Codeword* codeword = (CBC_Codeword*)codewords->GetAt(codewordsRow);\r
209     CFX_PtrArray* previousColumnCodewords = ((CBC_DetectionResultColumn*)m_detectionResultColumns.GetAt(barcodeColumn - 1))->getCodewords();\r
210     CFX_PtrArray* nextColumnCodewords = previousColumnCodewords;\r
211     if (m_detectionResultColumns[barcodeColumn + 1] != NULL) {\r
212         nextColumnCodewords = ((CBC_DetectionResultColumn*)m_detectionResultColumns[barcodeColumn + 1])->getCodewords();\r
213     }\r
214     CFX_PtrArray otherCodewords;\r
215     otherCodewords.SetSize(14);\r
216     otherCodewords[2] = previousColumnCodewords->GetAt(codewordsRow);\r
217     otherCodewords[3] = nextColumnCodewords->GetAt(codewordsRow);\r
218     if (codewordsRow > 0) {\r
219         otherCodewords[0] = codewords->GetAt(codewordsRow - 1);\r
220         otherCodewords[4] = previousColumnCodewords->GetAt(codewordsRow - 1);\r
221         otherCodewords[5] = nextColumnCodewords->GetAt(codewordsRow - 1);\r
222     }\r
223     if (codewordsRow > 1) {\r
224         otherCodewords[8] = codewords->GetAt(codewordsRow - 2);\r
225         otherCodewords[10] = previousColumnCodewords->GetAt(codewordsRow - 2);\r
226         otherCodewords[11] = nextColumnCodewords->GetAt(codewordsRow - 2);\r
227     }\r
228     if (codewordsRow < codewords->GetSize() - 1) {\r
229         otherCodewords[1] = codewords->GetAt(codewordsRow + 1);\r
230         otherCodewords[6] = previousColumnCodewords->GetAt(codewordsRow + 1);\r
231         otherCodewords[7] = nextColumnCodewords->GetAt(codewordsRow + 1);\r
232     }\r
233     if (codewordsRow < codewords->GetSize() - 2) {\r
234         otherCodewords[9] = codewords->GetAt(codewordsRow + 2);\r
235         otherCodewords[12] = previousColumnCodewords->GetAt(codewordsRow + 2);\r
236         otherCodewords[13] = nextColumnCodewords->GetAt(codewordsRow + 2);\r
237     }\r
238     for (FX_INT32 i = 0; i < otherCodewords.GetSize(); i++) {\r
239         CBC_Codeword* otherCodeword = (CBC_Codeword*)otherCodewords.GetAt(i);\r
240         if (adjustRowNumber(codeword, otherCodeword)) {\r
241             return;\r
242         }\r
243     }\r
244 }\r
245 FX_BOOL CBC_DetectionResult::adjustRowNumber(CBC_Codeword* codeword, CBC_Codeword* otherCodeword)\r
246 {\r
247     if (otherCodeword == NULL) {\r
248         return FALSE;\r
249     }\r
250     if (otherCodeword->hasValidRowNumber() && otherCodeword->getBucket() == codeword->getBucket()) {\r
251         codeword->setRowNumber(otherCodeword->getRowNumber());\r
252         return TRUE;\r
253     }\r
254     return FALSE;\r
255 }\r
256 FX_INT32 CBC_DetectionResult::getBarcodeColumnCount()\r
257 {\r
258     return m_barcodeColumnCount;\r
259 }\r
260 FX_INT32 CBC_DetectionResult::getBarcodeRowCount()\r
261 {\r
262     return m_barcodeMetadata->getRowCount();\r
263 }\r
264 FX_INT32 CBC_DetectionResult::getBarcodeECLevel()\r
265 {\r
266     return m_barcodeMetadata->getErrorCorrectionLevel();\r
267 }\r