|  | // Copyright 2014 The PDFium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 
|  | // Original code is licensed as follows: | 
|  | /* | 
|  | * Copyright 2011 ZXing authors | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #include "fxbarcode/oned/BC_OneDimWriter.h" | 
|  |  | 
|  | #include <math.h> | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <memory> | 
|  | #include <vector> | 
|  |  | 
|  | #include "build/build_config.h" | 
|  | #include "core/fxge/cfx_defaultrenderdevice.h" | 
|  | #include "core/fxge/cfx_fillrenderoptions.h" | 
|  | #include "core/fxge/cfx_font.h" | 
|  | #include "core/fxge/cfx_graphstatedata.h" | 
|  | #include "core/fxge/cfx_path.h" | 
|  | #include "core/fxge/cfx_renderdevice.h" | 
|  | #include "core/fxge/cfx_unicodeencodingex.h" | 
|  | #include "core/fxge/text_char_pos.h" | 
|  | #include "fxbarcode/BC_Writer.h" | 
|  |  | 
|  | // static | 
|  | bool CBC_OneDimWriter::HasValidContentSize(WideStringView contents) { | 
|  | // Limit the size of 1D barcodes. Typical 1D barcodes are short so this should | 
|  | // be sufficient for most use cases. | 
|  | static constexpr size_t kMaxInputLengthBytes = 8192; | 
|  |  | 
|  | size_t size = contents.GetLength(); | 
|  | return size > 0 && size <= kMaxInputLengthBytes; | 
|  | } | 
|  |  | 
|  | CBC_OneDimWriter::CBC_OneDimWriter() = default; | 
|  |  | 
|  | CBC_OneDimWriter::~CBC_OneDimWriter() = default; | 
|  |  | 
|  | void CBC_OneDimWriter::SetPrintChecksum(bool checksum) { | 
|  | m_bPrintChecksum = checksum; | 
|  | } | 
|  |  | 
|  | void CBC_OneDimWriter::SetDataLength(int32_t length) { | 
|  | m_iDataLenth = length; | 
|  | } | 
|  |  | 
|  | void CBC_OneDimWriter::SetCalcChecksum(bool state) { | 
|  | m_bCalcChecksum = state; | 
|  | } | 
|  |  | 
|  | bool CBC_OneDimWriter::SetFont(CFX_Font* cFont) { | 
|  | if (!cFont) | 
|  | return false; | 
|  |  | 
|  | m_pFont = cFont; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void CBC_OneDimWriter::SetFontSize(float size) { | 
|  | m_fFontSize = size; | 
|  | } | 
|  |  | 
|  | void CBC_OneDimWriter::SetFontStyle(int32_t style) { | 
|  | m_iFontStyle = style; | 
|  | } | 
|  |  | 
|  | void CBC_OneDimWriter::SetFontColor(FX_ARGB color) { | 
|  | m_fontColor = color; | 
|  | } | 
|  |  | 
|  | pdfium::span<uint8_t> CBC_OneDimWriter::AppendPattern( | 
|  | pdfium::span<uint8_t> target, | 
|  | pdfium::span<const uint8_t> pattern, | 
|  | bool startColor) { | 
|  | bool color = startColor; | 
|  | size_t added = 0; | 
|  | size_t pos = 0; | 
|  | for (const int8_t pattern_value : pattern) { | 
|  | for (int32_t i = 0; i < pattern_value; ++i) | 
|  | target[pos++] = color ? 1 : 0; | 
|  | added += pattern_value; | 
|  | color = !color; | 
|  | } | 
|  | return target.subspan(added); | 
|  | } | 
|  |  | 
|  | void CBC_OneDimWriter::CalcTextInfo(const ByteString& text, | 
|  | TextCharPos* charPos, | 
|  | CFX_Font* cFont, | 
|  | float geWidth, | 
|  | int32_t fontSize, | 
|  | float& charsLen) { | 
|  | std::unique_ptr<CFX_UnicodeEncodingEx> encoding = | 
|  | FX_CreateFontEncodingEx(cFont); | 
|  |  | 
|  | const size_t length = text.GetLength(); | 
|  | std::vector<uint32_t> charcodes(length); | 
|  | float charWidth = 0; | 
|  | for (size_t i = 0; i < length; ++i) { | 
|  | charcodes[i] = encoding->CharCodeFromUnicode(text[i]); | 
|  | int32_t glyph_code = encoding->GlyphFromCharCode(charcodes[i]); | 
|  | int glyph_value = cFont->GetGlyphWidth(glyph_code); | 
|  | float temp = glyph_value * fontSize / 1000.0; | 
|  | charWidth += temp; | 
|  | } | 
|  | charsLen = charWidth; | 
|  | float leftPositon = (float)(geWidth - charsLen) / 2.0f; | 
|  | if (leftPositon < 0 && geWidth == 0) { | 
|  | leftPositon = 0; | 
|  | } | 
|  | float penX = 0.0; | 
|  | float penY = (float)abs(cFont->GetDescent()) * (float)fontSize / 1000.0f; | 
|  | float left = leftPositon; | 
|  | float top = 0.0; | 
|  | charPos[0].m_Origin = CFX_PointF(penX + left, penY + top); | 
|  | charPos[0].m_GlyphIndex = encoding->GlyphFromCharCode(charcodes[0]); | 
|  | charPos[0].m_FontCharWidth = cFont->GetGlyphWidth(charPos[0].m_GlyphIndex); | 
|  | #if BUILDFLAG(IS_APPLE) | 
|  | charPos[0].m_ExtGID = charPos[0].m_GlyphIndex; | 
|  | #endif | 
|  | penX += (float)(charPos[0].m_FontCharWidth) * (float)fontSize / 1000.0f; | 
|  | for (size_t i = 1; i < length; i++) { | 
|  | charPos[i].m_Origin = CFX_PointF(penX + left, penY + top); | 
|  | charPos[i].m_GlyphIndex = encoding->GlyphFromCharCode(charcodes[i]); | 
|  | charPos[i].m_FontCharWidth = cFont->GetGlyphWidth(charPos[i].m_GlyphIndex); | 
|  | #if BUILDFLAG(IS_APPLE) | 
|  | charPos[i].m_ExtGID = charPos[i].m_GlyphIndex; | 
|  | #endif | 
|  | penX += (float)(charPos[i].m_FontCharWidth) * (float)fontSize / 1000.0f; | 
|  | } | 
|  | } | 
|  |  | 
|  | void CBC_OneDimWriter::ShowDeviceChars(CFX_RenderDevice* device, | 
|  | const CFX_Matrix& matrix, | 
|  | const ByteString str, | 
|  | float geWidth, | 
|  | TextCharPos* pCharPos, | 
|  | float locX, | 
|  | float locY, | 
|  | int32_t barWidth) { | 
|  | int32_t iFontSize = static_cast<int32_t>(fabs(m_fFontSize)); | 
|  | int32_t iTextHeight = iFontSize + 1; | 
|  | CFX_FloatRect rect((float)locX, (float)locY, (float)(locX + geWidth), | 
|  | (float)(locY + iTextHeight)); | 
|  | if (geWidth != m_Width) { | 
|  | rect.right -= 1; | 
|  | } | 
|  | FX_RECT re = matrix.TransformRect(rect).GetOuterRect(); | 
|  | device->FillRect(re, kBackgroundColor); | 
|  | CFX_Matrix affine_matrix(1.0, 0.0, 0.0, -1.0, (float)locX, | 
|  | (float)(locY + iFontSize)); | 
|  | affine_matrix.Concat(matrix); | 
|  | device->DrawNormalText(pdfium::make_span(pCharPos, str.GetLength()), m_pFont, | 
|  | static_cast<float>(iFontSize), affine_matrix, | 
|  | m_fontColor, GetTextRenderOptions()); | 
|  | } | 
|  |  | 
|  | bool CBC_OneDimWriter::ShowChars(WideStringView contents, | 
|  | CFX_RenderDevice* device, | 
|  | const CFX_Matrix& matrix, | 
|  | int32_t barWidth) { | 
|  | if (!device || !m_pFont) | 
|  | return false; | 
|  |  | 
|  | ByteString str = FX_UTF8Encode(contents); | 
|  | std::vector<TextCharPos> charpos(str.GetLength()); | 
|  | float charsLen = 0; | 
|  | float geWidth = 0; | 
|  | if (m_locTextLoc == BC_TEXT_LOC::kAboveEmbed || | 
|  | m_locTextLoc == BC_TEXT_LOC::kBelowEmbed) { | 
|  | geWidth = 0; | 
|  | } else if (m_locTextLoc == BC_TEXT_LOC::kAbove || | 
|  | m_locTextLoc == BC_TEXT_LOC::kBelow) { | 
|  | geWidth = (float)barWidth; | 
|  | } | 
|  | int32_t iFontSize = static_cast<int32_t>(fabs(m_fFontSize)); | 
|  | int32_t iTextHeight = iFontSize + 1; | 
|  | CalcTextInfo(str, charpos.data(), m_pFont, geWidth, iFontSize, charsLen); | 
|  | if (charsLen < 1) | 
|  | return true; | 
|  |  | 
|  | int32_t locX = 0; | 
|  | int32_t locY = 0; | 
|  | switch (m_locTextLoc) { | 
|  | case BC_TEXT_LOC::kAboveEmbed: | 
|  | locX = static_cast<int32_t>(barWidth - charsLen) / 2; | 
|  | locY = 0; | 
|  | geWidth = charsLen; | 
|  | break; | 
|  | case BC_TEXT_LOC::kAbove: | 
|  | locX = 0; | 
|  | locY = 0; | 
|  | geWidth = (float)barWidth; | 
|  | break; | 
|  | case BC_TEXT_LOC::kBelowEmbed: | 
|  | locX = static_cast<int32_t>(barWidth - charsLen) / 2; | 
|  | locY = m_Height - iTextHeight; | 
|  | geWidth = charsLen; | 
|  | break; | 
|  | case BC_TEXT_LOC::kBelow: | 
|  | default: | 
|  | locX = 0; | 
|  | locY = m_Height - iTextHeight; | 
|  | geWidth = (float)barWidth; | 
|  | break; | 
|  | } | 
|  | ShowDeviceChars(device, matrix, str, geWidth, charpos.data(), (float)locX, | 
|  | (float)locY, barWidth); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool CBC_OneDimWriter::RenderDeviceResult(CFX_RenderDevice* device, | 
|  | const CFX_Matrix& matrix, | 
|  | WideStringView contents) { | 
|  | if (m_output.empty()) | 
|  | return false; | 
|  |  | 
|  | CFX_GraphStateData stateData; | 
|  | CFX_Path path; | 
|  | path.AppendRect(0, 0, static_cast<float>(m_Width), | 
|  | static_cast<float>(m_Height)); | 
|  | device->DrawPath(path, &matrix, &stateData, kBackgroundColor, | 
|  | kBackgroundColor, CFX_FillRenderOptions::EvenOddOptions()); | 
|  | CFX_Matrix scaledMatrix(m_outputHScale, 0.0, 0.0, | 
|  | static_cast<float>(m_Height), 0.0, 0.0); | 
|  | scaledMatrix.Concat(matrix); | 
|  | for (const auto& rect : m_output) { | 
|  | CFX_GraphStateData data; | 
|  | device->DrawPath(rect, &scaledMatrix, &data, kBarColor, 0, | 
|  | CFX_FillRenderOptions::WindingOptions()); | 
|  | } | 
|  |  | 
|  | return m_locTextLoc == BC_TEXT_LOC::kNone || !contents.Contains(' ') || | 
|  | ShowChars(contents, device, matrix, m_barWidth); | 
|  | } | 
|  |  | 
|  | bool CBC_OneDimWriter::RenderResult(WideStringView contents, | 
|  | pdfium::span<const uint8_t> code) { | 
|  | if (code.empty()) | 
|  | return false; | 
|  |  | 
|  | m_ModuleHeight = std::max(m_ModuleHeight, 20); | 
|  | const size_t original_codelength = code.size(); | 
|  | const int32_t leftPadding = m_bLeftPadding ? 7 : 0; | 
|  | const int32_t rightPadding = m_bRightPadding ? 7 : 0; | 
|  | const size_t codelength = code.size() + leftPadding + rightPadding; | 
|  | m_outputHScale = | 
|  | m_Width > 0 ? static_cast<float>(m_Width) / static_cast<float>(codelength) | 
|  | : 1.0; | 
|  | m_barWidth = m_Width; | 
|  |  | 
|  | m_output.clear(); | 
|  | m_output.reserve(original_codelength); | 
|  | for (size_t i = 0; i < original_codelength; ++i) { | 
|  | if (code[i] != 1) | 
|  | continue; | 
|  |  | 
|  | size_t output_index = i + leftPadding; | 
|  | if (output_index >= codelength) | 
|  | return true; | 
|  |  | 
|  | m_output.emplace_back(); | 
|  | m_output.back().AppendRect(output_index, 0.0f, output_index + 1, 1.0f); | 
|  | } | 
|  | return true; | 
|  | } |