blob: ef6ec806d2bd27a8f576fcb27f3029c72eb04734 [file] [log] [blame]
// Copyright 2020 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/fxge/win32/ctext_only_printer_driver.h"
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <algorithm>
#include "core/fxcrt/fx_string.h"
#include "core/fxcrt/fx_system.h"
#include "core/fxge/cfx_font.h"
#include "core/fxge/text_char_pos.h"
#include "third_party/base/notreached.h"
CTextOnlyPrinterDriver::CTextOnlyPrinterDriver(HDC hDC)
: m_hDC(hDC),
m_Width(INT_MAX),
m_Height(INT_MAX),
m_HorzSize(INT_MAX),
m_VertSize(INT_MAX),
m_OriginY(0.0f),
m_SetOrigin(false) {
m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
}
CTextOnlyPrinterDriver::~CTextOnlyPrinterDriver() = default;
DeviceType CTextOnlyPrinterDriver::GetDeviceType() const {
return DeviceType::kPrinter;
}
int CTextOnlyPrinterDriver::GetDeviceCaps(int caps_id) const {
switch (caps_id) {
case FXDC_PIXEL_WIDTH:
return m_Width;
case FXDC_PIXEL_HEIGHT:
return m_Height;
case FXDC_BITS_PIXEL:
return m_nBitsPerPixel;
case FXDC_RENDER_CAPS:
return 0;
case FXDC_HORZ_SIZE:
return m_HorzSize;
case FXDC_VERT_SIZE:
return m_VertSize;
default:
NOTREACHED();
return 0;
}
}
bool CTextOnlyPrinterDriver::SetClip_PathFill(
const CFX_PathData* pPathData,
const CFX_Matrix* pObject2Device,
const CFX_FillRenderOptions& fill_options) {
return true;
}
bool CTextOnlyPrinterDriver::SetClip_PathStroke(
const CFX_PathData* pPathData,
const CFX_Matrix* pObject2Device,
const CFX_GraphStateData* pGraphState) {
return false;
}
bool CTextOnlyPrinterDriver::DrawPath(const CFX_PathData* pPathData,
const CFX_Matrix* pObject2Device,
const CFX_GraphStateData* pGraphState,
uint32_t fill_color,
uint32_t stroke_color,
const CFX_FillRenderOptions& fill_options,
BlendMode blend_type) {
return false;
}
bool CTextOnlyPrinterDriver::SetDIBits(const RetainPtr<CFX_DIBBase>& pBitmap,
uint32_t color,
const FX_RECT& src_rect,
int left,
int top,
BlendMode blend_type) {
return false;
}
bool CTextOnlyPrinterDriver::GetClipBox(FX_RECT* pRect) {
pRect->left = 0;
pRect->right = m_Width;
pRect->top = 0;
pRect->bottom = m_Height;
return true;
}
bool CTextOnlyPrinterDriver::StretchDIBits(
const RetainPtr<CFX_DIBBase>& pBitmap,
uint32_t color,
int dest_left,
int dest_top,
int dest_width,
int dest_height,
const FX_RECT* pClipRect,
const FXDIB_ResampleOptions& options,
BlendMode blend_type) {
return false;
}
bool CTextOnlyPrinterDriver::StartDIBits(
const RetainPtr<CFX_DIBBase>& pBitmap,
int bitmap_alpha,
uint32_t color,
const CFX_Matrix& matrix,
const FXDIB_ResampleOptions& options,
std::unique_ptr<CFX_ImageRenderer>* handle,
BlendMode blend_type) {
return false;
}
bool CTextOnlyPrinterDriver::DrawDeviceText(
int nChars,
const TextCharPos* pCharPos,
CFX_Font* pFont,
const CFX_Matrix& mtObject2Device,
float font_size,
uint32_t color,
const CFX_TextRenderOptions& /*options*/) {
if (g_pdfium_print_mode != 1)
return false;
if (nChars < 1 || !pFont || !pFont->IsEmbedded() || !pFont->IsTTFont())
return false;
// Scale factor used to minimize the kerning problems caused by rounding
// errors below. Value chosen based on the title of https://crbug.com/18383
const double kScaleFactor = 10;
// Detect new lines and add clrf characters (since this is Windows only).
// These characters are removed by SkPDF, but the new line information is
// preserved in the text location. clrf characters seem to be ignored by
// label printers that use this driver.
WideString wsText;
size_t len = nChars;
float fOffsetY = mtObject2Device.f * kScaleFactor;
if (m_SetOrigin && FXSYS_roundf(m_OriginY) != FXSYS_roundf(fOffsetY)) {
wsText += L"\r\n";
len += 2;
}
wsText.Reserve(len);
m_OriginY = fOffsetY;
m_SetOrigin = true;
// Text
for (int i = 0; i < nChars; ++i) {
// Only works with PDFs from Skia's PDF generator. Cannot handle arbitrary
// values from PDFs.
const TextCharPos& charpos = pCharPos[i];
ASSERT(charpos.m_AdjustMatrix[0] == 0);
ASSERT(charpos.m_AdjustMatrix[1] == 0);
ASSERT(charpos.m_AdjustMatrix[2] == 0);
ASSERT(charpos.m_AdjustMatrix[3] == 0);
ASSERT(charpos.m_Origin.y == 0);
wsText += charpos.m_Unicode;
}
ByteString text = wsText.ToDefANSI();
auto text_span = text.span();
while (!text_span.empty()) {
uint8_t buffer[1026];
size_t send_len = std::min<size_t>(text_span.size(), 1024);
*(reinterpret_cast<uint16_t*>(buffer)) = static_cast<uint16_t>(send_len);
memcpy(buffer + 2, text_span.data(), send_len);
::GdiComment(m_hDC, send_len + 2, buffer);
text_span = text_span.subspan(send_len);
}
return true;
}