File indexing completed on 2024-12-01 12:33:50
0001 /* 0002 Large image displaying library. 0003 0004 Copyright (C) 2004,2005 Maks Orlovich (maksim@kde.org) 0005 Copyright (C) 2012 Martin Sandsmark (martin.sandsmark@kde.org) 0006 0007 Permission is hereby granted, free of charge, to any person obtaining a copy 0008 of this software and associated documentation files (the "Software"), to deal 0009 in the Software without restriction, including without limitation the rights 0010 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 0011 copies of the Software, and to permit persons to whom the Software is 0012 furnished to do so, subject to the following conditions: 0013 0014 The above copyright notice and this permission notice shall be included in 0015 all copies or substantial portions of the Software. 0016 0017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0020 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 0021 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 0022 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0023 0024 */ 0025 #include "scaledimageplane.h" 0026 #include "imagemanager.h" 0027 0028 namespace khtmlImLoad 0029 { 0030 ScaledImagePlane::ScaledImagePlane(unsigned int _width, unsigned int _height, RawImagePlane *_parent): 0031 ImagePlane(_width, _height), parent(_parent), tiles(tilesWidth, tilesHeight), m_width(_width), m_height(_height) 0032 { 0033 } 0034 0035 bool ScaledImagePlane::isUpToDate(unsigned int tileX, unsigned int tileY, 0036 PixmapTile *tile) 0037 { 0038 Q_UNUSED(tileX); 0039 if (!tile->pixmap) { 0040 return false; 0041 } 0042 0043 int yStep = (parent->image.height() << 8) / height; 0044 for (unsigned int line = 0, srcLine = 0; line < tileHeight(tileY); ++line, srcLine += yStep) { 0045 if (tile->versions[line] < parent->versions[(srcLine + yStep) >> 8]) { 0046 return false; 0047 } 0048 } 0049 0050 return true; 0051 } 0052 0053 // Trick from here: https://www.compuphase.com/graphic/scale3.htm 0054 #define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) ) 0055 static void scaleLoop32bit(QImage *dst, const QImage &src, int tileX, int tileY, 0056 int height, int width, unsigned char *versions, unsigned char *parentVersions) 0057 { 0058 int yStep = (src.height() << 8) / height; // We bitshift for when we get large ratios 0059 int xStep = (src.width() << 8) / width; 0060 for (int yTarget = 0, ySource = tileY * Tile::TileSize * yStep; yTarget < dst->height(); yTarget++, ySource += yStep) { 0061 const quint32 *srcBelow = reinterpret_cast<const quint32 *>(src.scanLine(ySource >> 8)); 0062 const quint32 *srcAbove = reinterpret_cast<const quint32 *>(src.scanLine((ySource + yStep / 2) >> 8)); 0063 quint32 *destination = reinterpret_cast<quint32 *>(dst->scanLine(yTarget)); 0064 0065 versions[yTarget] = parentVersions[ySource >> 8]; 0066 for (int xTarget = 0, xSource = tileX * Tile::TileSize * xStep; xTarget < dst->width(); xTarget++, xSource += xStep) { 0067 quint32 average1 = AVG(srcBelow[xSource >> 8], srcAbove[(xSource + xStep / 2) >> 8]); 0068 quint32 average2 = AVG(srcBelow[(xSource + xStep / 2) >> 8], srcAbove[xSource >> 8]); 0069 destination[xTarget] = AVG(average1, average2); 0070 } 0071 } 0072 } 0073 0074 static void scaleLoop8bit(QImage *dst, const QImage &src, int tileX, int tileY, 0075 int height, int width, unsigned char *versions, unsigned char *parentVersions) 0076 { 0077 int yStep = (src.height() << 8) / height; // We bitshift for when we get large ratios 0078 int xStep = (src.width() << 8) / width; 0079 for (int yTarget = 0, ySource = tileY * Tile::TileSize * yStep; yTarget < dst->height(); yTarget++, ySource += yStep) { 0080 const quint8 *srcPix = reinterpret_cast<const quint8 *>(src.scanLine(ySource >> 8)); 0081 quint8 *destination = reinterpret_cast<quint8 *>(dst->scanLine(yTarget)); 0082 versions[yTarget] = parentVersions[ySource >> 8]; 0083 for (int xTarget = 0, xSource = tileX * Tile::TileSize * xStep; xTarget < dst->width(); xTarget++, xSource += xStep) { 0084 destination[xTarget] = srcPix[xSource >> 8]; 0085 } 0086 } 0087 } 0088 0089 void ScaledImagePlane::flushCache() 0090 { 0091 for (unsigned tileX = 0; tileX < tilesWidth; ++tileX) { 0092 for (unsigned tileY = 0; tileY < tilesHeight; ++tileY) { 0093 ImageTile &imageTile = tiles.at(tileX, tileY); 0094 if (!imageTile.image.isNull()) { 0095 ImageManager::imageCache()->removeEntry(&imageTile); 0096 } 0097 } 0098 } 0099 } 0100 0101 void ScaledImagePlane::ensureUpToDate(unsigned int tileX, unsigned int tileY, 0102 PixmapTile *tile) 0103 { 0104 ImageTile &imageTile = tiles.at(tileX, tileY); 0105 0106 //Create the image if need be. 0107 if (imageTile.image.isNull()) { 0108 imageTile.image = parent->format.makeImage(tileWidth(tileX), 0109 tileHeight(tileY)); 0110 ImageManager::imageCache()->addEntry(&imageTile); 0111 std::memset(imageTile.versions, 0, Tile::TileSize); 0112 } else { 0113 ImageManager::imageCache()->touchEntry(&imageTile); 0114 } 0115 0116 // Do the actual scaling 0117 if (parent->format.depth() == 1) { 0118 scaleLoop8bit(&imageTile.image, parent->image, tileX, tileY, m_height, m_width, imageTile.versions, parent->versions); 0119 } else { 0120 scaleLoop32bit(&imageTile.image, parent->image, tileX, tileY, m_height, m_width, imageTile.versions, parent->versions); 0121 } 0122 0123 //Now, push stuff into the pixmap. 0124 updatePixmap(tile, imageTile.image, tileX, tileY, 0, 0, imageTile.versions); 0125 } 0126 0127 ScaledImagePlane::~ScaledImagePlane() 0128 { 0129 } 0130 0131 } 0132