diff options
-rw-r--r-- | dw/fltkimgbuf.cc | 31 | ||||
-rw-r--r-- | dw/fltkimgbuf.hh | 3 | ||||
-rw-r--r-- | dw/imgbuf.hh | 13 | ||||
-rw-r--r-- | dw/layout.cc | 2 | ||||
-rw-r--r-- | dw/style.cc | 110 | ||||
-rw-r--r-- | dw/style.hh | 10 | ||||
-rw-r--r-- | test/dw_image_background.cc | 4 |
7 files changed, 142 insertions, 31 deletions
diff --git a/dw/fltkimgbuf.cc b/dw/fltkimgbuf.cc index 81d2dc2d..e526ad60 100644 --- a/dw/fltkimgbuf.cc +++ b/dw/fltkimgbuf.cc @@ -427,6 +427,37 @@ int FltkImgbuf::getRootHeight () return root ? root->height : height; } +core::Imgbuf *FltkImgbuf::createSimilarBuf (int width, int height) +{ + return new FltkImgbuf (type, width, height, gamma); +} + +void FltkImgbuf::copyTo (Imgbuf *dest, int xDestRoot, int yDestRoot, + int xSrc, int ySrc, int widthSrc, int heightSrc) +{ + FltkImgbuf *fDest = (FltkImgbuf*)dest; + assert (bpp == fDest->bpp); + + int xSrc2 = lout::misc::min (xSrc + widthSrc, fDest->width - xDestRoot); + int ySrc2 = lout::misc::min (ySrc + heightSrc, fDest->height - yDestRoot); + + //printf ("copying from (%d, %d), %d x %d to (%d, %d) (root) => " + // "xSrc2 = %d, ySrc2 = %d\n", + // xSrc, ySrc, widthSrc, heightSrc, xDestRoot, yDestRoot, + // xSrc2, ySrc2); + + for (int x = xSrc; x < xSrc2; x++) + for (int y = ySrc; y < ySrc2; y++) { + int iSrc = x + width * y; + int iDest = xDestRoot + x + fDest->width * (yDestRoot + y); + + //printf (" (%d, %d): %d -> %d\n", x, y, iSrc, iDest); + + for (int b = 0; b < bpp; b++) + fDest->rawdata[bpp * iDest + b] = rawdata[bpp * iSrc + b]; + } +} + void FltkImgbuf::ref () { refCount++; diff --git a/dw/fltkimgbuf.hh b/dw/fltkimgbuf.hh index ee5ae922..0b8b5549 100644 --- a/dw/fltkimgbuf.hh +++ b/dw/fltkimgbuf.hh @@ -73,6 +73,9 @@ public: void getRowArea (int row, dw::core::Rectangle *area); int getRootWidth (); int getRootHeight (); + core::Imgbuf *createSimilarBuf (int width, int height); + void copyTo (Imgbuf *dest, int xDestRoot, int yDestRoot, + int xSrc, int ySrc, int widthSrc, int heightSrc); void ref (); void unref (); diff --git a/dw/imgbuf.hh b/dw/imgbuf.hh index 02ba9087..3ccbe3c5 100644 --- a/dw/imgbuf.hh +++ b/dw/imgbuf.hh @@ -178,6 +178,19 @@ public: virtual int getRootWidth () = 0; virtual int getRootHeight () = 0; + + /** + * Creates an image buffer with same parameters (type, gamma etc.) + * except size. + */ + virtual Imgbuf *createSimilarBuf (int width, int height) = 0; + + /** + * Copies another image buffer into this image buffer. + */ + virtual void copyTo (Imgbuf *dest, int xDestRoot, int yDestRoot, + int xSrc, int ySrc, int widthSrc, int heightSrc) = 0; + /* * Reference counting. */ diff --git a/dw/layout.cc b/dw/layout.cc index 8e1f065c..89361881 100644 --- a/dw/layout.cc +++ b/dw/layout.cc @@ -580,7 +580,7 @@ void Layout::draw (View *view, Rectangle *area) // First of all, draw background image. (Unlike background *color*, // this is not a feature of the views.) - if (bgImage != NULL && bgImage->getImgbuf() != NULL) + if (bgImage != NULL && bgImage->getImgbufSrc() != NULL) style::drawBackgroundImage (view, bgImage, bgRepeat, bgAttachment, bgPositionX, bgPositionY, area->x, area->y, area->width, diff --git a/dw/style.cc b/dw/style.cc index 4a8325d8..3b57ffcf 100644 --- a/dw/style.cc +++ b/dw/style.cc @@ -36,6 +36,11 @@ namespace style { const bool drawBackgroundLineByLine = true; +const int MIN_BG_IMG_W = 10; +const int MIN_BG_IMG_H = 10; +const int OPT_BG_IMG_W = 50; +const int OPT_BG_IMG_H = 50; + static void calcBackgroundRelatedValues (StyleImage *backgroundImage, BackgroundRepeat backgroundRepeat, BackgroundAttachment @@ -469,17 +474,59 @@ Tooltip *Tooltip::create (Layout *layout, const char *text) void StyleImage::StyleImgRenderer::setBuffer (core::Imgbuf *buffer, bool resize) { - if (image->imgbuf) - image->imgbuf->unref (); - - image->imgbuf = buffer; - if (image->imgbuf) - image->imgbuf->ref (); + if (image->imgbufSrc) + image->imgbufSrc->unref (); + if (image->imgbufTiled) + image->imgbufTiled->unref (); + + image->imgbufTiled = NULL; + + image->imgbufSrc = buffer; + if (image->imgbufSrc) { + image->imgbufSrc->ref (); + + // If the image is too small, drawing a background will cause + // many calls of View::drawImgbuf. For this reason, we create + // another image buffer, the "tiled" image buffer, which is + // larger (the "optimal" size is defined as OPT_BG_IMG_W * + // OPT_BG_IMG_H) and contains the "source" buffer several times. + + if (image->imgbufSrc->getRootWidth() * image->imgbufSrc->getRootHeight() + < MIN_BG_IMG_W * MIN_BG_IMG_H) { + image->tilesX = + misc::max (OPT_BG_IMG_W / image->imgbufSrc->getRootWidth(), 1); + image->tilesY = + misc::max (OPT_BG_IMG_H / image->imgbufSrc->getRootHeight(), 1); + image->imgbufTiled = + image->imgbufSrc->createSimilarBuf + (image->tilesX * image->imgbufSrc->getRootWidth(), + image->tilesY * image->imgbufSrc->getRootHeight()); + } + } } void StyleImage::StyleImgRenderer::drawRow (int row) { - // Nothing to do. + if (image->imgbufTiled) { + // A row of data has been copied to the source buffer, here it + // is copied into the tiled buffer. + + // Unfortunately, this code may be called *after* some other + // implementations of ImgRenderer::drawRow, which actually + // *draw* the tiled buffer, which is so not up to date + // (ImgRendererDist does not define an order). OTOH, these + // drawing implementations calle Widget::queueResize, so the + // actual drawing (and so access to the tiled buffer) is done + // later. + + int w = image->imgbufSrc->getRootWidth (); + int h = image->imgbufSrc->getRootHeight (); + + for (int x = 0; x < image->tilesX; x++) + for (int y = 0; y < image->tilesX; y++) + image->imgbufSrc->copyTo (image->imgbufTiled, x * w, y * h, + 0, row, w, 1); + } } void StyleImage::StyleImgRenderer::finish () @@ -497,7 +544,8 @@ StyleImage::StyleImage () //printf ("new StyleImage %p\n", this); refCount = 0; - imgbuf = NULL; + imgbufSrc = NULL; + imgbufTiled = NULL; imgRendererDist = new ImgRendererDist (); styleImgRenderer = new StyleImgRenderer (this); @@ -508,8 +556,10 @@ StyleImage::~StyleImage () { //printf ("delete StyleImage %p\n", this); - if (imgbuf) - imgbuf->unref (); + if (imgbufSrc) + imgbufSrc->unref (); + if (imgbufTiled) + imgbufTiled->unref (); delete imgRendererDist; delete styleImgRenderer; @@ -528,7 +578,7 @@ void StyleImage::ExternalImgRenderer::drawRow (int row) if (readyToDraw () && (backgroundImage = getBackgroundImage ())) { // All single rows are drawn. - Imgbuf *imgbuf = backgroundImage->getImgbuf(); + Imgbuf *imgbuf = backgroundImage->getImgbufSrc(); int imgWidth = imgbuf->getRootWidth (); int imgHeight = imgbuf->getRootHeight (); @@ -1093,7 +1143,7 @@ void drawBackground (View *view, Layout *layout, Rectangle *area, // has to be compared, ... (!atTop || layout->getBgColor () != style->backgroundColor); bool bgImage = (style->backgroundImage != NULL && - style->backgroundImage->getImgbuf() != NULL) && + style->backgroundImage->getImgbufSrc() != NULL) && // ... but for backgrounds, it would be rather complicated. To handle the // two cases (normal HTML in a viewport, where the layout background // image is set, and contents of <button> within a flat view, where the @@ -1144,10 +1194,6 @@ void drawBackgroundImage (View *view, StyleImage *backgroundImage, int x, int y, int width, int height, int xRef, int yRef, int widthRef, int heightRef) { - Imgbuf *imgbuf = backgroundImage->getImgbuf(); - int imgWidth = imgbuf->getRootWidth (); - int imgHeight = imgbuf->getRootHeight (); - //printf ("drawBackgroundImage (..., [img: %d, %d], ..., (%d, %d), %d x %d, " // "(%d, %d), %d x %d)\n", imgWidth, imgHeight, x, y, width, height, // xRef, yRef, widthRef, heightRef); @@ -1165,19 +1211,33 @@ void drawBackgroundImage (View *view, StyleImage *backgroundImage, //printf ("tileX1 = %d, tileX2 = %d, tileY1 = %d, tileY2 = %d\n", // tileX1, tileX2, tileY1, tileY2); - if (doDraw) - for (int tileX = tileX1; tileX <= tileX2; tileX++) - for (int tileY = tileY1; tileY <= tileY2; tileY++) { - int xt = origX + tileX * imgWidth; + if (doDraw) { + // Drawing is done with the "tiled" buffer, but all calculations + // before have been done with the "source" buffer. + + Imgbuf *imgbufS = backgroundImage->getImgbufSrc(); + int imgWidthS = imgbufS->getRootWidth (); + int imgHeightS = imgbufS->getRootHeight (); + + Imgbuf *imgbufT = backgroundImage->getImgbufTiled(); + int imgWidthT = imgbufT->getRootWidth (); + int imgHeightT = imgbufT->getRootHeight (); + int tilesX = backgroundImage->getTilesX (); + int tilesY = backgroundImage->getTilesY (); + + for (int tileX = tileX1; tileX <= tileX2; tileX += tilesX) + for (int tileY = tileY1; tileY <= tileY2; tileY += tilesY) { + int xt = origX + tileX * imgWidthS; int x1 = misc::max (xt, x); - int x2 = misc::min (xt + imgWidth, x + width); - int yt = origY + tileY * imgHeight; + int x2 = misc::min (xt + imgWidthT, x + width); + int yt = origY + tileY * imgHeightS; int y1 = misc::max (yt, y); - int y2 = misc::min (yt + imgHeight, y + height); + int y2 = misc::min (yt + imgHeightT, y + height); - view->drawImage (imgbuf, xt, yt, x1 - xt, y1 - yt, + view->drawImage (imgbufT, xt, yt, x1 - xt, y1 - yt, x2 - x1, y2 - y1); } + } } void calcBackgroundRelatedValues (StyleImage *backgroundImage, @@ -1192,7 +1252,7 @@ void calcBackgroundRelatedValues (StyleImage *backgroundImage, int *tileX1, int *tileX2, int *tileY1, int *tileY2, bool *doDraw) { - Imgbuf *imgbuf = backgroundImage->getImgbuf(); + Imgbuf *imgbuf = backgroundImage->getImgbufSrc(); int imgWidth = imgbuf->getRootWidth (); int imgHeight = imgbuf->getRootHeight (); diff --git a/dw/style.hh b/dw/style.hh index 752f6a64..ce8e2e6f 100644 --- a/dw/style.hh +++ b/dw/style.hh @@ -748,8 +748,8 @@ private: void fatal (); }; - int refCount; - Imgbuf *imgbuf; + int refCount, tilesX, tilesY; + Imgbuf *imgbufSrc, *imgbufTiled; ImgRendererDist *imgRendererDist; StyleImgRenderer *styleImgRenderer; @@ -826,7 +826,11 @@ public: inline void unref () { if (--refCount == 0) delete this; } - inline Imgbuf *getImgbuf () { return imgbuf; } + inline Imgbuf *getImgbufSrc () { return imgbufSrc; } + inline Imgbuf *getImgbufTiled () + { return imgbufTiled ? imgbufTiled : imgbufSrc; } + inline int getTilesX () { return imgbufTiled ? tilesX : 1; } + inline int getTilesY () { return imgbufTiled ? tilesY : 1; } inline ImgRenderer *getMainImgRenderer () { return imgRendererDist; } /** diff --git a/test/dw_image_background.cc b/test/dw_image_background.cc index ad50924d..24966850 100644 --- a/test/dw_image_background.cc +++ b/test/dw_image_background.cc @@ -71,8 +71,8 @@ static void imageInitTimeout (void *data) static void imageDrawTimeout (void *data) { - Imgbuf *imgbuf1 = image1 ? image1->getImgbuf () : NULL; - Imgbuf *imgbuf2 = image2 ? image2->getImgbuf () : NULL; + Imgbuf *imgbuf1 = image1 ? image1->getImgbufSrc () : NULL; + Imgbuf *imgbuf2 = image2 ? image2->getImgbufSrc () : NULL; if (imgbuf1 && imgRow1 < 200) { byte buf[3 * 400]; |