File indexing completed on 2024-05-19 15:12:19

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