Files
DocumentServer-v-9.2.0/core/PdfFile/lib/xpdf/TileCompositor.cc
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

453 lines
11 KiB
C++

//========================================================================
//
// TileCompositor.cc
//
// Copyright 2014 Glyph & Cog, LLC
//
//========================================================================
#include <aconf.h>
#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
#include <string.h>
#include <math.h>
#include "gmempp.h"
#include "GString.h"
#include "GList.h"
#include "SplashBitmap.h"
#include "GlobalParams.h"
#include "DisplayState.h"
#include "TileMap.h"
#include "TileCache.h"
#include "TileCompositor.h"
//------------------------------------------------------------------------
// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
static inline Guchar div255(int x) {
return (Guchar)((x + (x >> 8) + 0x80) >> 8);
}
//------------------------------------------------------------------------
TileCompositor::TileCompositor(DisplayState *stateA,
TileMap *tileMapA,
TileCache *tileCacheA) {
state = stateA;
state->setTileCompositor(this);
tileMap = tileMapA;
tileCache = tileCacheA;
bitmap = NULL;
bitmapValid = gFalse;
}
TileCompositor::~TileCompositor() {
delete bitmap;
}
SplashBitmap *TileCompositor::getBitmap(GBool *finished) {
GList *tiles;
PlacedTileDesc *tile;
SplashBitmap *tileBitmap;
GBool allTilesFinished, tileFinished;
int xSrc, ySrc, xDest, yDest, w, h, i;
if (bitmapValid) {
*finished = gTrue;
return bitmap;
}
if (!bitmap ||
bitmap->getWidth() != state->getWinW() ||
bitmap->getHeight() != state->getWinH()) {
if (bitmap) {
delete bitmap;
}
bitmap = new SplashBitmap(state->getWinW(), state->getWinH(),
state->getBitmapRowPad(), state->getColorMode(),
gFalse, gTrue, NULL);
}
clearBitmap();
//--- PDF content
allTilesFinished = gTrue;
tiles = tileMap->getTileList();
tileCache->setActiveTileList(tiles);
for (i = 0; i < tiles->getLength(); ++i) {
tile = (PlacedTileDesc *)tiles->get(i);
if (tile->px >= 0) {
xSrc = 0;
xDest = tile->px;
w = tile->tw;
} else {
xSrc = -tile->px;
xDest = 0;
w = tile->tw + tile->px;
}
if (xDest + w > state->getWinW()) {
w = state->getWinW() - xDest;
}
if (tile->py >= 0) {
ySrc = 0;
yDest = tile->py;
h = tile->th;
} else {
ySrc = -tile->py;
yDest = 0;
h = tile->th + tile->py;
}
if (yDest + h > state->getWinH()) {
h = state->getWinH() - yDest;
}
if (w > 0 && h > 0) {
if ((tileBitmap = tileCache->getTileBitmap(tile, &tileFinished))) {
blit(tileBitmap, xSrc, ySrc,
bitmap, xDest, yDest, w, h, !tileFinished);
} else {
fill(xDest, yDest, w, h, state->getPaperColor());
}
allTilesFinished &= tileFinished;
}
}
//--- selection
if (state->hasSelection()) {
drawSelection();
}
if (finished) {
*finished = allTilesFinished;
}
bitmapValid = allTilesFinished;
return bitmap;
}
void TileCompositor::drawSelection() {
SelectRect *rect;
int x0, y0, x1, y1, t, i;
for (i = 0; i < state->getNumSelectRects(); ++i) {
rect = state->getSelectRect(i);
tileMap->cvtUserToWindow(rect->page, rect->x0, rect->y0, &x0, &y0);
tileMap->cvtUserToWindow(rect->page, rect->x1, rect->y1, &x1, &y1);
if (x0 > x1) {
t = x0; x0 = x1; x1 = t;
}
if (y0 > y1) {
t = y0; y0 = y1; y1 = t;
}
if (x0 < 0) {
x0 = 0;
} else if (x0 > state->getWinW()) {
x0 = state->getWinW();
}
if (y0 < 0) {
y0 = 0;
} else if (y0 > state->getWinH()) {
y0 = state->getWinH();
}
if (x1 < 0) {
x1 = 0;
} else if (x1 > state->getWinW()) {
x1 = state->getWinW();
}
if (y1 < 0) {
y1 = 0;
} else if (y1 > state->getWinH()) {
y1 = state->getWinH();
}
// NB: in any of the non-continuous modes, if selectPage isn't
// displayed, cvtUserToWindow will return 0,0 -- so we need to
// check for x0 < x1 and y0 < y1 here
if (x0 < x1 && y0 < y1) {
applySelection(x0, y0, x1 - x0, y1 - y0, state->getSelectColor());
}
}
}
void TileCompositor::paperColorChanged() {
bitmapValid = gFalse;
}
void TileCompositor::matteColorChanged() {
bitmapValid = gFalse;
}
void TileCompositor::selectColorChanged() {
bitmapValid = gFalse;
}
void TileCompositor::reverseVideoChanged() {
bitmapValid = gFalse;
}
void TileCompositor::docChanged() {
bitmapValid = gFalse;
}
void TileCompositor::windowSizeChanged() {
bitmapValid = gFalse;
}
void TileCompositor::displayModeChanged() {
bitmapValid = gFalse;
}
void TileCompositor::zoomChanged() {
bitmapValid = gFalse;
}
void TileCompositor::rotateChanged() {
bitmapValid = gFalse;
}
void TileCompositor::scrollPositionChanged() {
bitmapValid = gFalse;
}
void TileCompositor::selectionChanged() {
bitmapValid = gFalse;
}
void TileCompositor::regionsChanged() {
bitmapValid = gFalse;
}
void TileCompositor::optionalContentChanged() {
bitmapValid = gFalse;
}
void TileCompositor::forceRedraw() {
bitmapValid = gFalse;
}
// Clear the bitmap to matteColor. This only supports the RGB8 and
// BGR8 color modes.
void TileCompositor::clearBitmap() {
SplashColorPtr data, row, p;
SplashBitmapRowSize rowSize;
int w, h, x, y;
w = bitmap->getWidth();
h = bitmap->getHeight();
rowSize = bitmap->getRowSize();
data = bitmap->getDataPtr();
switch (state->getColorMode()) {
case splashModeRGB8:
if (state->getMatteColor()[0] == state->getMatteColor()[1] &&
state->getMatteColor()[1] == state->getMatteColor()[2]) {
if (rowSize < 0) {
memset(data + rowSize * (h - 1), state->getMatteColor()[0],
-rowSize * h);
} else {
memset(data, state->getMatteColor()[0], rowSize * h);
}
} else {
row = data;
for (y = 0; y < h; ++y) {
p = row;
for (x = 0; x < w; ++x) {
*p++ = state->getMatteColor()[0];
*p++ = state->getMatteColor()[1];
*p++ = state->getMatteColor()[2];
}
row += rowSize;
}
}
break;
case splashModeBGR8:
if (state->getMatteColor()[0] == state->getMatteColor()[1] &&
state->getMatteColor()[1] == state->getMatteColor()[2]) {
if (rowSize < 0) {
memset(data + rowSize * (h - 1), state->getMatteColor()[0],
-rowSize * h);
} else {
memset(data, state->getMatteColor()[0], rowSize * h);
}
} else {
row = data;
for (y = 0; y < h; ++y) {
p = row;
for (x = 0; x < w; ++x) {
*p++ = state->getMatteColor()[2];
*p++ = state->getMatteColor()[1];
*p++ = state->getMatteColor()[0];
}
row += rowSize;
}
}
break;
default:
break;
}
}
// Copy [xSrc, ySrc, w, h] from srcBitmap to [xDest, yDest] in
// destBitmap. This only supports the RGB8 and BGR8 color modes.
// If [compositeWithPaper] is true, composites the source bitmap
// with the paper color (used for incremental updates).
void TileCompositor::blit(SplashBitmap *srcBitmap, int xSrc, int ySrc,
SplashBitmap *destBitmap, int xDest, int yDest,
int w, int h, GBool compositeWithPaper) {
SplashColorPtr srcData, destData, srcP, destP;
SplashColorPtr paperColor;
Guchar *alphaData, *alphaP;
Guchar alpha, alpha1;
SplashBitmapRowSize srcRowSize, destRowSize;
size_t alphaRowSize;
int x, y;
srcData = srcBitmap->getDataPtr();
srcRowSize = srcBitmap->getRowSize();
destData = destBitmap->getDataPtr();
destRowSize = destBitmap->getRowSize();
if (compositeWithPaper && (alphaData = srcBitmap->getAlphaPtr())) {
alphaRowSize = srcBitmap->getAlphaRowSize();
paperColor = state->getPaperColor();
for (y = 0; y < h; ++y) {
destP = &destData[(yDest + y) * destRowSize + 3 * xDest];
srcP = &srcData[(ySrc + y) * srcRowSize + 3 * xSrc];
alphaP = &alphaData[(ySrc + y) * alphaRowSize + xSrc];
for (x = 0; x < w; ++x) {
alpha = *alphaP++;
//~ this needs to swap paperColor 0/1/2 in BGR8 mode (?)
if (alpha == 255) {
destP[0] = srcP[0];
destP[1] = srcP[1];
destP[2] = srcP[2];
} else if (alpha == 0) {
destP[0] = paperColor[0];
destP[1] = paperColor[1];
destP[2] = paperColor[2];
} else {
alpha1 = (Guchar)(255 - alpha);
destP[0] = div255(alpha1 * paperColor[0] + alpha * srcP[0]);
destP[1] = div255(alpha1 * paperColor[1] + alpha * srcP[1]);
destP[2] = div255(alpha1 * paperColor[2] + alpha * srcP[2]);
}
srcP += 3;
destP += 3;
}
}
} else {
for (y = 0; y < h; ++y) {
destP = &destData[(yDest + y) * destRowSize + 3 * xDest];
srcP = &srcData[(ySrc + y) * srcRowSize + 3 * xSrc];
memcpy(destP, srcP, 3 * w);
}
}
}
// Fill [xDest, yDest, w, h] with color. This only supports the RGB8
// and BGR8 color modes.
void TileCompositor::fill(int xDest, int yDest, int w, int h,
SplashColorPtr color) {
SplashColorPtr data, p;
Guchar c0, c1, c2;
SplashBitmapRowSize rowSize;
int x, y;
if (xDest < 0) {
w += xDest;
xDest = 0;
}
if (xDest + w > state->getWinW()) {
w = state->getWinW() - xDest;
}
if (w <= 0) {
return;
}
if (yDest < 0) {
h += yDest;
yDest = 0;
}
if (yDest + h > state->getWinH()) {
h = state->getWinH() - yDest;
}
if (h <= 0) {
return;
}
data = bitmap->getDataPtr();
rowSize = bitmap->getRowSize();
if (bitmap->getMode() == splashModeRGB8) {
c0 = color[0];
c1 = color[1];
c2 = color[2];
} else {
c0 = color[2];
c1 = color[1];
c2 = color[0];
}
for (y = 0; y < h; ++y) {
p = &data[(yDest + y) * rowSize + 3 * xDest];
for (x = 0; x < w; ++x) {
p[0] = c0;
p[1] = c1;
p[2] = c2;
p += 3;
}
}
}
// Apply a selection of <color> to the specified rectangle. This only
// supports the RGB8 and BGR8 color modes.
void TileCompositor::applySelection(int xDest, int yDest, int w, int h,
SplashColorPtr color) {
SplashColorPtr data, p;
Guchar c0, c1, c2;
SplashBitmapRowSize rowSize;
int x, y;
if (xDest < 0) {
w += xDest;
xDest = 0;
}
if (xDest + w > state->getWinW()) {
w = state->getWinW() - xDest;
}
if (w <= 0) {
return;
}
if (yDest < 0) {
h += yDest;
yDest = 0;
}
if (yDest + h > state->getWinH()) {
h = state->getWinH() - yDest;
}
if (h <= 0) {
return;
}
data = bitmap->getDataPtr();
rowSize = bitmap->getRowSize();
if (bitmap->getMode() == splashModeRGB8) {
c0 = color[0];
c1 = color[1];
c2 = color[2];
} else {
c0 = color[2];
c1 = color[1];
c2 = color[0];
}
for (y = 0; y < h; ++y) {
p = &data[(yDest + y) * rowSize + 3 * xDest];
for (x = 0; x < w; ++x) {
p[0] = (Guchar)((3 * p[0] + c0) / 4);
p[1] = (Guchar)((3 * p[1] + c1) / 4);
p[2] = (Guchar)((3 * p[2] + c2) / 4);
p += 3;
}
}
}
//------------------------------------------------------------------------