mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-04-10 19:15:13 +00:00
229 lines
6 KiB
Plaintext
229 lines
6 KiB
Plaintext
//========================================================================
|
|
//
|
|
// BBoxOutputDev.cc
|
|
//
|
|
// This file is licensed under the GPLv2 or later
|
|
//
|
|
// Copyright 2020 sgerwk <sgerwk@aol.com>
|
|
// Copyright 2022 Oliver Sander <oliver.sander@tu-dresden.de>
|
|
//
|
|
//========================================================================
|
|
|
|
#include <cmath>
|
|
#include <BBoxOutputDev.h>
|
|
#include <GfxFont.h>
|
|
|
|
#define writingModeHorizontal 0
|
|
#define writingModeVertical 1
|
|
|
|
BBoxOutputDev::BBoxOutputDev() : BBoxOutputDev(true, true, true) { }
|
|
|
|
BBoxOutputDev::BBoxOutputDev(bool textA, bool vectorA, bool rasterA) : BBoxOutputDev(textA, vectorA, rasterA, true) { }
|
|
|
|
BBoxOutputDev::BBoxOutputDev(bool textA, bool vectorA, bool rasterA, bool lwidthA)
|
|
{
|
|
hasGraphics = false;
|
|
text = textA;
|
|
vector = vectorA;
|
|
raster = rasterA;
|
|
lwidth = lwidthA;
|
|
}
|
|
|
|
double BBoxOutputDev::getX1() const
|
|
{
|
|
return bb.x1;
|
|
}
|
|
|
|
double BBoxOutputDev::getY1() const
|
|
{
|
|
return bb.y1;
|
|
}
|
|
|
|
double BBoxOutputDev::getX2() const
|
|
{
|
|
return bb.x2;
|
|
}
|
|
|
|
double BBoxOutputDev::getY2() const
|
|
{
|
|
return bb.y2;
|
|
}
|
|
|
|
double BBoxOutputDev::getHasGraphics() const
|
|
{
|
|
return hasGraphics;
|
|
}
|
|
|
|
void BBoxOutputDev::endPage() { }
|
|
|
|
void BBoxOutputDev::stroke(GfxState *state)
|
|
{
|
|
updatePath(&bb, state->getPath(), state);
|
|
}
|
|
|
|
void BBoxOutputDev::fill(GfxState *state)
|
|
{
|
|
updatePath(&bb, state->getPath(), state);
|
|
}
|
|
|
|
void BBoxOutputDev::eoFill(GfxState *state)
|
|
{
|
|
updatePath(&bb, state->getPath(), state);
|
|
}
|
|
|
|
void BBoxOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg)
|
|
{
|
|
updateImage(&bb, state);
|
|
}
|
|
|
|
void BBoxOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, const int *maskColors, bool inlineImg)
|
|
{
|
|
updateImage(&bb, state);
|
|
}
|
|
|
|
void BBoxOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, bool maskInvert, bool maskInterpolate)
|
|
{
|
|
updateImage(&bb, state);
|
|
}
|
|
|
|
void BBoxOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap,
|
|
bool maskInterpolate)
|
|
{
|
|
updateImage(&bb, state);
|
|
}
|
|
|
|
void BBoxOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, const Unicode *u, int uLen)
|
|
{
|
|
double leftent, rightent, ascent, descent;
|
|
const double *fm, *fb;
|
|
double fontSize, w, adjust;
|
|
double fx, fy;
|
|
|
|
if (!text) {
|
|
return;
|
|
}
|
|
|
|
const GfxFont *const font = state->getFont().get();
|
|
if (!font) {
|
|
return;
|
|
}
|
|
|
|
if (code == (CharCode)0x20) {
|
|
return;
|
|
}
|
|
|
|
fontSize = state->getFontSize();
|
|
|
|
fb = font->getFontBBox();
|
|
if (font->getWMode() == writingModeHorizontal) {
|
|
leftent = 0;
|
|
rightent = 0;
|
|
ascent = font->getAscent();
|
|
descent = font->getDescent();
|
|
} else {
|
|
if (fb[0] == 0 && fb[1] == 0 && fb[2] == 0 && fb[3] == 0) {
|
|
leftent = -0.5;
|
|
rightent = 0.5;
|
|
} else {
|
|
leftent = fb[1];
|
|
rightent = fb[3];
|
|
}
|
|
ascent = 0;
|
|
descent = 0;
|
|
}
|
|
|
|
if (font->getType() != fontType3) {
|
|
adjust = 1;
|
|
} else {
|
|
// adjust font size for type3 fonts,
|
|
// similar to TextPage::updateFont()
|
|
w = ((Gfx8BitFont *)font)->getWidth(code);
|
|
adjust = w / 0.5;
|
|
fm = font->getFontMatrix();
|
|
if (fm[0] != 0) {
|
|
adjust *= fabs(fm[3] / fm[0]);
|
|
}
|
|
}
|
|
|
|
ascent *= adjust * fontSize;
|
|
descent *= adjust * fontSize;
|
|
leftent *= adjust * fontSize;
|
|
rightent *= adjust * fontSize;
|
|
|
|
state->textTransformDelta(leftent, descent, &fx, &fy);
|
|
updatePoint(&bb, fx + x, fy + y, state);
|
|
|
|
state->textTransformDelta(rightent, ascent, &fx, &fy);
|
|
updatePoint(&bb, fx + x, fy + y, state);
|
|
|
|
state->textTransformDelta(leftent, descent, &fx, &fy);
|
|
updatePoint(&bb, fx + x + dx, fy + y + dy, state);
|
|
|
|
state->textTransformDelta(rightent, ascent, &fx, &fy);
|
|
updatePoint(&bb, fx + x + dx, fy + y + dy, state);
|
|
}
|
|
|
|
/* update the bounding box with a new point */
|
|
void BBoxOutputDev::updatePoint(PDFRectangle *bbA, double x, double y, const GfxState *state)
|
|
{
|
|
Matrix o = { 1, 0, 0, 1, 0, 0 };
|
|
double tx, ty;
|
|
double xMin, yMin, xMax, yMax;
|
|
|
|
state->getClipBBox(&xMin, &yMin, &xMax, &yMax);
|
|
|
|
o.scale(1, -1);
|
|
o.translate(0, -state->getPageHeight());
|
|
|
|
state->transform(x, y, &tx, &ty);
|
|
tx = tx < xMin ? xMin : tx > xMax ? xMax : tx;
|
|
ty = ty < yMin ? yMin : ty > yMax ? yMax : ty;
|
|
o.transform(tx, ty, &x, &y);
|
|
|
|
if (!hasGraphics || bbA->x1 > x) {
|
|
bbA->x1 = x;
|
|
}
|
|
if (!hasGraphics || bbA->y1 > y) {
|
|
bbA->y1 = y;
|
|
}
|
|
if (!hasGraphics || bbA->x2 < x) {
|
|
bbA->x2 = x;
|
|
}
|
|
if (!hasGraphics || bbA->y2 < y) {
|
|
bbA->y2 = y;
|
|
}
|
|
hasGraphics = true;
|
|
}
|
|
|
|
/* update the bounding box with a new path */
|
|
void BBoxOutputDev::updatePath(PDFRectangle *bbA, const GfxPath *path, const GfxState *state)
|
|
{
|
|
int i, j;
|
|
const GfxSubpath *subpath;
|
|
double x, y;
|
|
double w;
|
|
if (!vector) {
|
|
return;
|
|
}
|
|
w = lwidth ? state->getLineWidth() : 0;
|
|
for (i = 0; i < path->getNumSubpaths(); i++) {
|
|
subpath = path->getSubpath(i);
|
|
for (j = 0; j < subpath->getNumPoints(); j++) {
|
|
x = subpath->getX(j);
|
|
y = subpath->getY(j);
|
|
updatePoint(bbA, x - w / 2, y - w / 2, state);
|
|
updatePoint(bbA, x + w / 2, y + w / 2, state);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* update the bounding box with a new image */
|
|
void BBoxOutputDev::updateImage(PDFRectangle *bbA, const GfxState *state)
|
|
{
|
|
if (!raster) {
|
|
return;
|
|
}
|
|
updatePoint(bbA, 0, 1, state);
|
|
updatePoint(bbA, 1, 0, state);
|
|
}
|