diff options
author | Sebastian Geerken <devnull@localhost> | 2013-12-09 14:44:42 +0100 |
---|---|---|
committer | Sebastian Geerken <devnull@localhost> | 2013-12-09 14:44:42 +0100 |
commit | 01f697091153846bdffc73b3150ba37c763301cc (patch) | |
tree | 84773dff07a8498e7cc62695d89a6ecb29378a82 /dw | |
parent | ee66f4f97e38d11e68b9515b7043aa8ac6f63c74 (diff) | |
parent | 6c7572f8bd23064f96ba716e1ba8ba8a34847001 (diff) |
Merge (large!).
Diffstat (limited to 'dw')
-rw-r--r-- | dw/Makefile.am | 2 | ||||
-rw-r--r-- | dw/alignedtextblock.cc | 2 | ||||
-rw-r--r-- | dw/core.hh | 1 | ||||
-rw-r--r-- | dw/findtext.cc | 3 | ||||
-rw-r--r-- | dw/fltkflatview.cc | 2 | ||||
-rw-r--r-- | dw/fltkimgbuf.cc | 67 | ||||
-rw-r--r-- | dw/fltkimgbuf.hh | 3 | ||||
-rw-r--r-- | dw/fltkplatform.cc | 4 | ||||
-rw-r--r-- | dw/fltkviewport.cc | 3 | ||||
-rw-r--r-- | dw/image.cc | 12 | ||||
-rw-r--r-- | dw/image.hh | 5 | ||||
-rw-r--r-- | dw/imgbuf.hh | 13 | ||||
-rw-r--r-- | dw/imgrenderer.cc | 48 | ||||
-rw-r--r-- | dw/imgrenderer.hh | 87 | ||||
-rw-r--r-- | dw/layout.cc | 128 | ||||
-rw-r--r-- | dw/layout.hh | 31 | ||||
-rw-r--r-- | dw/listitem.cc | 2 | ||||
-rw-r--r-- | dw/selection.cc | 3 | ||||
-rw-r--r-- | dw/style.cc | 465 | ||||
-rw-r--r-- | dw/style.hh | 158 | ||||
-rw-r--r-- | dw/table.cc | 2 | ||||
-rw-r--r-- | dw/tablecell.cc | 2 | ||||
-rw-r--r-- | dw/textblock.cc | 199 | ||||
-rw-r--r-- | dw/textblock.hh | 52 | ||||
-rw-r--r-- | dw/textblock_linebreaking.cc | 17 | ||||
-rw-r--r-- | dw/ui.cc | 2 | ||||
-rw-r--r-- | dw/widget.cc | 163 | ||||
-rw-r--r-- | dw/widget.hh | 24 |
28 files changed, 1390 insertions, 110 deletions
diff --git a/dw/Makefile.am b/dw/Makefile.am index aa5c88c3..47ec5275 100644 --- a/dw/Makefile.am +++ b/dw/Makefile.am @@ -14,6 +14,8 @@ libDw_core_a_SOURCES = \ findtext.cc \ findtext.hh \ imgbuf.hh \ + imgrenderer.hh \ + imgrenderer.cc \ iterator.cc \ iterator.hh \ layout.cc \ diff --git a/dw/alignedtextblock.cc b/dw/alignedtextblock.cc index dde408b2..0d910c93 100644 --- a/dw/alignedtextblock.cc +++ b/dw/alignedtextblock.cc @@ -20,6 +20,7 @@ #include "alignedtextblock.hh" +#include "../lout/debug.hh" #include <stdio.h> namespace dw { @@ -62,6 +63,7 @@ int AlignedTextblock::CLASS_ID = -1; AlignedTextblock::AlignedTextblock (bool limitTextWidth): Textblock (limitTextWidth) { + DBG_OBJ_CREATE ("dw::AlignedTextblock"); registerName ("dw::AlignedTextblock", &CLASS_ID); } @@ -44,6 +44,7 @@ class ResourceFactory; #include "types.hh" #include "events.hh" #include "imgbuf.hh" +#include "imgrenderer.hh" #include "style.hh" #include "view.hh" #include "platform.hh" diff --git a/dw/findtext.cc b/dw/findtext.cc index 19485078..e86116f1 100644 --- a/dw/findtext.cc +++ b/dw/findtext.cc @@ -20,6 +20,7 @@ #include "core.hh" +#include "../lout/debug.hh" #include "../lout/msg.h" namespace dw { @@ -27,6 +28,8 @@ namespace core { FindtextState::FindtextState () { + DBG_OBJ_CREATE ("dw::core::FindtextState"); + key = NULL; nexttab = NULL; widget = NULL; diff --git a/dw/fltkflatview.cc b/dw/fltkflatview.cc index b9e85d99..d40c59e5 100644 --- a/dw/fltkflatview.cc +++ b/dw/fltkflatview.cc @@ -20,6 +20,7 @@ #include "fltkflatview.hh" +#include "../lout/debug.hh" #include <stdio.h> @@ -31,6 +32,7 @@ namespace fltk { FltkFlatView::FltkFlatView (int x, int y, int w, int h, const char *label): FltkWidgetView (x, y, w, h, label) { + DBG_OBJ_CREATE ("dw::fltk::FltkFlatView"); } FltkFlatView::~FltkFlatView () diff --git a/dw/fltkimgbuf.cc b/dw/fltkimgbuf.cc index 81d2dc2d..d9d653ec 100644 --- a/dw/fltkimgbuf.cc +++ b/dw/fltkimgbuf.cc @@ -143,7 +143,7 @@ void FltkImgbuf::init (Type type, int width, int height, double gamma, scaledBuffers = new lout::container::typed::List <FltkImgbuf> (true); else scaledBuffers = NULL; - + if (!isRoot()) { // Scaling for (int row = 0; row < root->height; row++) { @@ -228,31 +228,33 @@ inline void FltkImgbuf::scaleRowBeautiful (int row, const core::byte *data) { int sr1 = scaledY (row); int sr2 = scaledY (row + 1); + bool allRootRows = false; - for (int sr = sr1; sr < sr2; sr++) - copiedRows->set (sr, true); + // Don't rescale rows! + if (copiedRows->get(sr1)) return; - if (height > root->height) + if (height > root->height) { scaleBuffer (data, root->width, 1, rawdata + sr1 * width * bpp, width, sr2 - sr1, bpp, gamma); - else { - assert (sr1 ==sr2 || sr1 + 1 == sr2); + // Mark scaled rows done + for (int sr = sr1; sr < sr2 || sr == sr1; sr++) + copiedRows->set (sr, true); + } else { + assert (sr1 == sr2 || sr1 + 1 == sr2); int row1 = backscaledY(sr1), row2 = backscaledY(sr1 + 1); - // Draw only when all original lines are retrieved (speed). - bool allRootRows = true; - for (int r = row1; allRootRows && r < row2; r++) - allRootRows = allRootRows && root->copiedRows->get(r); - - if (allRootRows) - // We have to access root->rawdata (which has to be up to - // date), since a larger area than the single row is accessed - // here. + // Check all the necessary root lines already arrived, + // a larger area than a single row may be accessed here. + for (int r=row1; (allRootRows=root->copiedRows->get(r)) && ++r < row2; ); + if (allRootRows) { scaleBuffer (root->rawdata + row1 * root->width * bpp, root->width, row2 - row1, rawdata + sr1 * width * bpp, width, 1, bpp, gamma); + // Mark scaled row done + copiedRows->set (sr1, true); + } } } @@ -295,7 +297,7 @@ inline void FltkImgbuf::scaleBuffer (const core::byte *src, int srcWidth, int yo1 = y * srcHeight / destHeight; int yo2 = lout::misc::max ((y + 1) * srcHeight / destHeight, yo1 + 1); int n = (xo2 - xo1) * (yo2 - yo1); - + int v[bpp]; for(int i = 0; i < bpp; i++) v[i] = 0; @@ -328,7 +330,7 @@ void FltkImgbuf::copyRow (int row, const core::byte *data) for (Iterator <FltkImgbuf> it = scaledBuffers->iterator(); it.hasNext(); ) { FltkImgbuf *sb = it.getNext (); - sb->scaleRow(row, data); + sb->scaleRow (row, data); } } } @@ -427,6 +429,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/fltkplatform.cc b/dw/fltkplatform.cc index 1d77e289..2a160d63 100644 --- a/dw/fltkplatform.cc +++ b/dw/fltkplatform.cc @@ -20,6 +20,7 @@ #include <stdio.h> #include "../lout/msg.h" +#include "../lout/debug.hh" #include "fltkcore.hh" #include <FL/fl_draw.H> @@ -454,6 +455,8 @@ core::ui::RadioButtonResource FltkPlatform::FltkPlatform () { + DBG_OBJ_CREATE ("dw::fltk::FltkPlatform"); + layout = NULL; idleQueue = new container::typed::List <IdleFunc> (true); idleFuncRunning = false; @@ -476,6 +479,7 @@ FltkPlatform::~FltkPlatform () void FltkPlatform::setLayout (core::Layout *layout) { this->layout = layout; + DBG_OBJ_ASSOC_CHILD (layout); } diff --git a/dw/fltkviewport.cc b/dw/fltkviewport.cc index de4c8f94..7e91a83a 100644 --- a/dw/fltkviewport.cc +++ b/dw/fltkviewport.cc @@ -27,6 +27,7 @@ #include <stdio.h> #include "../lout/msg.h" +#include "../lout/debug.hh" using namespace lout; using namespace lout::object; @@ -53,6 +54,8 @@ public: FltkViewport::FltkViewport (int X, int Y, int W, int H, const char *label): FltkWidgetView (X, Y, W, H, label) { + DBG_OBJ_CREATE ("dw::fltk::FltkViewport"); + hscrollbar = new CustScrollbar (x (), y (), 1, 1); hscrollbar->type(FL_HORIZONTAL); hscrollbar->callback (hscrollbarCallback, this); diff --git a/dw/image.cc b/dw/image.cc index 1cb9ce39..3aef42ac 100644 --- a/dw/image.cc +++ b/dw/image.cc @@ -22,6 +22,7 @@ #include "image.hh" #include "../lout/msg.h" #include "../lout/misc.hh" +#include "../lout/debug.hh" namespace dw { @@ -143,6 +144,7 @@ int Image::CLASS_ID = -1; Image::Image(const char *altText) { + DBG_OBJ_CREATE ("dw::Image"); registerName ("dw::Image", &CLASS_ID); this->altText = altText ? strdup (altText) : NULL; altTextWidth = -1; // not yet calculated @@ -450,6 +452,16 @@ void Image::drawRow (int row) area.width, area.height); } +void Image::finish () +{ + // Nothing to do; images are always drawn line by line. +} + +void Image::fatal () +{ + // Could display an error. +} + /** * \brief Sets image as server side image map. diff --git a/dw/image.hh b/dw/image.hh index a8314d4f..a712936e 100644 --- a/dw/image.hh +++ b/dw/image.hh @@ -116,7 +116,7 @@ public: * * \sa\ref dw-images-and-backgrounds */ -class Image: public core::Widget +class Image: public core::Widget, public core::ImgRenderer { private: char *altText; @@ -157,6 +157,9 @@ public: void drawRow (int row); + void finish (); + void fatal (); + void setIsMap (); void setUseMap (ImageMapsList *list, Object *key); 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/imgrenderer.cc b/dw/imgrenderer.cc new file mode 100644 index 00000000..285a8dcd --- /dev/null +++ b/dw/imgrenderer.cc @@ -0,0 +1,48 @@ +#include "core.hh" + +namespace dw { +namespace core { + +using namespace lout::container; +using namespace lout::object; + +void ImgRendererDist::setBuffer (core::Imgbuf *buffer, bool resize) +{ + for (typed::Iterator <TypedPointer <ImgRenderer> > it = + children->iterator (); it.hasNext (); ) { + TypedPointer <ImgRenderer> *tp = it.getNext (); + tp->getTypedValue()->setBuffer (buffer, resize); + } +} + +void ImgRendererDist::drawRow (int row) +{ + for (typed::Iterator <TypedPointer <ImgRenderer> > it = + children->iterator (); it.hasNext (); ) { + TypedPointer <ImgRenderer> *tp = it.getNext (); + tp->getTypedValue()->drawRow (row); + } +} + + +void ImgRendererDist::finish () +{ + for (typed::Iterator <TypedPointer <ImgRenderer> > it = + children->iterator (); it.hasNext (); ) { + TypedPointer <ImgRenderer> *tp = it.getNext (); + tp->getTypedValue()->finish (); + } +} + +void ImgRendererDist::fatal () +{ + for (typed::Iterator <TypedPointer <ImgRenderer> > it = + children->iterator (); it.hasNext (); ) { + TypedPointer <ImgRenderer> *tp = it.getNext (); + tp->getTypedValue()->fatal (); + } +} + + +} // namespace core +} // namespace dw diff --git a/dw/imgrenderer.hh b/dw/imgrenderer.hh new file mode 100644 index 00000000..325a1998 --- /dev/null +++ b/dw/imgrenderer.hh @@ -0,0 +1,87 @@ +#ifndef __DW_IMGRENDERER_HH__ +#define __DW_IMGRENDERER_HH__ + +#ifndef __INCLUDED_FROM_DW_CORE_HH__ +# error Do not include this file directly, use "core.hh" instead. +#endif + +namespace dw { +namespace core { + +/** + * \brief ... + * + * \sa \ref dw-images-and-backgrounds + */ +class ImgRenderer +{ +public: + virtual ~ImgRenderer () { } + + /** + * \brief Called, when an image buffer is attached. + * + * This is typically the case when all meta data (size, depth) has been read. + */ + virtual void setBuffer (core::Imgbuf *buffer, bool resize = false) = 0; + + /** + * \brief Called, when data from a row is available and has been copied into + * the image buffer. + * + * The implementation will typically queue the respective area for drawing. + */ + virtual void drawRow (int row) = 0; + + /** + * \brief Called, when all image data has been retrieved. + * + * The implementation may use this instead of "drawRow" for drawing, to + * limit the number of draws. + */ + virtual void finish () = 0; + + /** + * \brief Called, when there are problems with the retrieval of image data. + * + * The implementation may use this to indicate an error. + */ + virtual void fatal () = 0; +}; + +/** + * \brief Implementation of ImgRenderer, which distributes all calls + * to a set of other implementations of ImgRenderer. + * + * The order of the call children is not defined, especially not + * identical to the order in which they have been added. + */ +class ImgRendererDist: public ImgRenderer +{ + lout::container::typed::HashSet <lout::object::TypedPointer <ImgRenderer> > + *children; + +public: + inline ImgRendererDist () + { children = new lout::container::typed::HashSet + <lout::object::TypedPointer <ImgRenderer> > (true); } + ~ImgRendererDist () { delete children; } + + void setBuffer (core::Imgbuf *buffer, bool resize); + void drawRow (int row); + void finish (); + void fatal (); + + void put (ImgRenderer *child) + { children->put (new lout::object::TypedPointer <ImgRenderer> (child)); } + void remove (ImgRenderer *child) + { lout::object::TypedPointer <ImgRenderer> tp (child); + children->remove (&tp); } +}; + +} // namespace core +} // namespace dw + +#endif // __DW_IMGRENDERER_HH__ + + diff --git a/dw/layout.cc b/dw/layout.cc index 4879bb1e..ff121250 100644 --- a/dw/layout.cc +++ b/dw/layout.cc @@ -32,6 +32,65 @@ using namespace lout::object; namespace dw { namespace core { +bool Layout::LayoutImgRenderer::readyToDraw () +{ + return true; +} + +void Layout::LayoutImgRenderer::getBgArea (int *x, int *y, int *width, + int *height) +{ + // TODO Actually not padding area, but visible area? + getRefArea (x, y, width, height); +} + +void Layout::LayoutImgRenderer::getRefArea (int *xRef, int *yRef, int *widthRef, + int *heightRef) +{ + *xRef = 0; + *yRef = 0; + *widthRef = misc::max (layout->viewportWidth + - (layout->canvasHeightGreater ? + layout->vScrollbarThickness : 0), + layout->canvasWidth); + *heightRef = misc::max (layout->viewportHeight + - layout->hScrollbarThickness, + layout->canvasAscent + layout->canvasDescent); +} + +style::StyleImage *Layout::LayoutImgRenderer::getBackgroundImage () +{ + return layout->bgImage; +} + +style::BackgroundRepeat Layout::LayoutImgRenderer::getBackgroundRepeat () +{ + return layout->bgRepeat; +} + +style::BackgroundAttachment + Layout::LayoutImgRenderer::getBackgroundAttachment () +{ + return layout->bgAttachment; +} + +style::Length Layout::LayoutImgRenderer::getBackgroundPositionX () +{ + return layout->bgPositionX; +} + +style::Length Layout::LayoutImgRenderer::getBackgroundPositionY () +{ + return layout->bgPositionY; +} + +void Layout::LayoutImgRenderer::draw (int x, int y, int width, int height) +{ + layout->queueDraw (x, y, width, height); +} + +// ---------------------------------------------------------------------- + void Layout::Receiver::canvasSizeChanged (int width, int ascent, int descent) { } @@ -188,9 +247,10 @@ Layout::Layout (Platform *platform) queueResizeList = new typed::Vector<Widget> (4, false); - DBG_OBJ_CREATE (this, "DwRenderLayout"); + DBG_OBJ_CREATE ("dw::core::Layout"); bgColor = NULL; + bgImage = NULL; cursor = style::CURSOR_DEFAULT; canvasWidth = canvasAscent = canvasDescent = 0; @@ -212,8 +272,8 @@ Layout::Layout (Platform *platform) textZone = new misc::ZoneAllocator (16 * 1024); - DBG_OBJ_ASSOC (&findtextState, this); - DBG_OBJ_ASSOC (&selectionState, this); + DBG_OBJ_ASSOC_CHILD (&findtextState); + DBG_OBJ_ASSOC_CHILD (&selectionState); platform->setLayout (this); @@ -221,18 +281,28 @@ Layout::Layout (Platform *platform) queueResizeCounter = sizeAllocateCounter = sizeRequestCounter = getExtremesCounter = 0; + + layoutImgRenderer = NULL; } Layout::~Layout () { widgetAtPoint = NULL; + if (layoutImgRenderer) { + if (bgImage) + bgImage->removeExternalImgRenderer (layoutImgRenderer); + delete layoutImgRenderer; + } + if (scrollIdleId != -1) platform->removeIdle (scrollIdleId); if (resizeIdleId != -1) platform->removeIdle (resizeIdleId); if (bgColor) bgColor->unref (); + if (bgImage) + bgImage->unref (); if (topLevel) { Widget *w = topLevel; topLevel = NULL; @@ -297,6 +367,8 @@ void Layout::removeWidget () void Layout::setWidget (Widget *widget) { + DBG_OBJ_ASSOC_CHILD (widget); + widgetAtPoint = NULL; if (topLevel) { Widget *w = topLevel; @@ -320,6 +392,8 @@ void Layout::attachView (View *view) if (this->view) MSG_ERR("attachView: Multiple views for layout!\n"); + DBG_OBJ_ASSOC_CHILD (view); + this->view = view; platform->attachView (view); @@ -521,6 +595,23 @@ void Layout::draw (View *view, Rectangle *area) { Rectangle widgetArea, intersection, widgetDrawArea; + // First of all, draw background image. (Unlike background *color*, + // this is not a feature of the views.) + if (bgImage != NULL && bgImage->getImgbufSrc() != NULL) + style::drawBackgroundImage (view, bgImage, bgRepeat, bgAttachment, + bgPositionX, bgPositionY, + area->x, area->y, area->width, + area->height, 0, 0, + // Reference area: maximum of canvas size and + // viewport size. + misc::max (viewportWidth + - (canvasHeightGreater ? + vScrollbarThickness : 0), + canvasWidth), + misc::max (viewportHeight + - hScrollbarThickness, + canvasAscent + canvasDescent)); + if (scrollIdleId != -1) { /* scroll is pending, defer draw until after scrollIdle() */ drawAfterScrollReq = true; @@ -663,6 +754,37 @@ void Layout::setBgColor (style::Color *color) view->setBgColor (bgColor); } +void Layout::setBgImage (style::StyleImage *bgImage, + style::BackgroundRepeat bgRepeat, + style::BackgroundAttachment bgAttachment, + style::Length bgPositionX, style::Length bgPositionY) +{ + if (layoutImgRenderer && this->bgImage) + this->bgImage->removeExternalImgRenderer (layoutImgRenderer); + + if (bgImage) + bgImage->ref (); + + if (this->bgImage) + this->bgImage->unref (); + + this->bgImage = bgImage; + this->bgRepeat = bgRepeat; + this->bgAttachment = bgAttachment; + this->bgPositionX = bgPositionX; + this->bgPositionY = bgPositionY; + + if (bgImage) { + // Create instance of LayoutImgRenderer when needed. Until this + // layout is deleted, "layoutImgRenderer" will be kept, since it + // is not specific to the style, but only to this layout. + if (layoutImgRenderer == NULL) + layoutImgRenderer = new LayoutImgRenderer (this); + bgImage->putExternalImgRenderer (layoutImgRenderer); + } +} + + void Layout::resizeIdle () { enterQueueResize (); diff --git a/dw/layout.hh b/dw/layout.hh index 2055b751..64274714 100644 --- a/dw/layout.hh +++ b/dw/layout.hh @@ -17,6 +17,27 @@ class Layout: public lout::object::Object { friend class Widget; +private: + class LayoutImgRenderer: public style::StyleImage::ExternalImgRenderer + { + Layout *layout; + + public: + LayoutImgRenderer (Layout *layout) { this->layout = layout; } + + bool readyToDraw (); + void getBgArea (int *x, int *y, int *width, int *height); + void getRefArea (int *xRef, int *yRef, int *widthRef, int *heightRef); + style::StyleImage *getBackgroundImage (); + style::BackgroundRepeat getBackgroundRepeat (); + style::BackgroundAttachment getBackgroundAttachment (); + style::Length getBackgroundPositionX (); + style::Length getBackgroundPositionY (); + void draw (int x, int y, int width, int height); + }; + + LayoutImgRenderer *layoutImgRenderer; + public: /** * \brief Receiver interface different signals. @@ -136,6 +157,11 @@ private: /* The state, which must be projected into the view. */ style::Color *bgColor; + style::StyleImage *bgImage; + style::BackgroundRepeat bgRepeat; + style::BackgroundAttachment bgAttachment; + style::Length bgPositionX, bgPositionY; + style::Cursor cursor; int canvasWidth, canvasAscent, canvasDescent; @@ -397,8 +423,13 @@ public: inline void resetSearch () { findtextState.resetSearch (); } void setBgColor (style::Color *color); + void setBgImage (style::StyleImage *bgImage, + style::BackgroundRepeat bgRepeat, + style::BackgroundAttachment bgAttachment, + style::Length bgPositionX, style::Length bgPositionY); inline style::Color* getBgColor () { return bgColor; } + inline style::StyleImage* getBgImage () { return bgImage; } }; } // namespace core diff --git a/dw/listitem.cc b/dw/listitem.cc index ed7a2c75..11086a9e 100644 --- a/dw/listitem.cc +++ b/dw/listitem.cc @@ -20,6 +20,7 @@ #include "listitem.hh" +#include "../lout/debug.hh" #include <stdio.h> namespace dw { @@ -29,6 +30,7 @@ int ListItem::CLASS_ID = -1; ListItem::ListItem (ListItem *ref, bool limitTextWidth): AlignedTextblock (limitTextWidth) { + DBG_OBJ_CREATE ("dw::ListItem"); registerName ("dw::ListItem", &CLASS_ID); setRefTextblock (ref); } diff --git a/dw/selection.cc b/dw/selection.cc index 8b4cf318..2201af44 100644 --- a/dw/selection.cc +++ b/dw/selection.cc @@ -20,6 +20,7 @@ #include "core.hh" +#include "../lout/debug.hh" #include <string.h> @@ -45,6 +46,8 @@ namespace core { SelectionState::SelectionState () { + DBG_OBJ_CREATE ("dw::core::SelectionState"); + layout = NULL; selectionState = NONE; diff --git a/dw/style.cc b/dw/style.cc index 51dda098..3f39a39e 100644 --- a/dw/style.cc +++ b/dw/style.cc @@ -32,6 +32,27 @@ namespace dw { namespace core { namespace style { +const bool drawBackgroundLineByLine = false; + +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 + backgroundAttachment, + Length backgroundPositionX, + Length backgroundPositionY, + int xDraw, int yDraw, int widthDraw, + int heightDraw, int xRef, int yRef, + int widthRef, int heightRef, + bool *repeatX, bool *repeatY, + int *origX, int *origY, + int *tileX1, int *tileX2, int *tileY1, + int *tileY2, bool *doDraw); + void StyleAttrs::initValues () { x_link = -1; @@ -46,6 +67,11 @@ void StyleAttrs::initValues () listStyleType = LIST_STYLE_TYPE_DISC; valign = VALIGN_BASELINE; backgroundColor = NULL; + backgroundImage = NULL; + backgroundRepeat = BACKGROUND_REPEAT; + backgroundAttachment = BACKGROUND_ATTACHMENT_SCROLL; + backgroundPositionX = createPerLength (0); + backgroundPositionY = createPerLength (0); width = height = lineHeight = LENGTH_AUTO; vloat = FLOAT_NONE; clear = CLEAR_NONE; @@ -83,6 +109,11 @@ void StyleAttrs::resetValues () top = bottom = left = right = LENGTH_AUTO; /** \todo Correct? Check specification. */ backgroundColor = NULL; + backgroundImage = NULL; + backgroundRepeat = BACKGROUND_REPEAT; + backgroundAttachment = BACKGROUND_ATTACHMENT_SCROLL; + backgroundPositionX = createPerLength (0); + backgroundPositionY = createPerLength (0); width = LENGTH_AUTO; height = LENGTH_AUTO; @@ -123,6 +154,11 @@ bool StyleAttrs::equals (object::Object *other) { textDecoration == otherAttrs->textDecoration && color == otherAttrs->color && backgroundColor == otherAttrs->backgroundColor && + backgroundImage == otherAttrs->backgroundImage && + backgroundRepeat == otherAttrs->backgroundRepeat && + backgroundAttachment == otherAttrs->backgroundAttachment && + backgroundPositionX == otherAttrs->backgroundPositionX && + backgroundPositionY == otherAttrs->backgroundPositionY && textAlign == otherAttrs->textAlign && valign == otherAttrs->valign && textAlignChar == otherAttrs->textAlignChar && @@ -170,6 +206,11 @@ int StyleAttrs::hashValue () { textDecoration + (intptr_t) color + (intptr_t) backgroundColor + + (intptr_t) backgroundImage + + backgroundRepeat + + backgroundAttachment + + backgroundPositionX + + backgroundPositionY + textAlign + valign + textAlignChar + @@ -226,6 +267,8 @@ Style::Style (StyleAttrs *attrs) color->ref (); if (backgroundColor) backgroundColor->ref (); + if (backgroundImage) + backgroundImage->ref (); if (borderColor.top) borderColor.top->ref(); if (borderColor.bottom) @@ -248,6 +291,8 @@ Style::~Style () color->unref (); if (backgroundColor) backgroundColor->unref (); + if (backgroundImage) + backgroundImage->unref (); if (borderColor.top) borderColor.top->unref(); if (borderColor.bottom) @@ -269,6 +314,11 @@ void Style::copyAttrs (StyleAttrs *attrs) textDecoration = attrs->textDecoration; color = attrs->color; backgroundColor = attrs->backgroundColor; + backgroundImage = attrs->backgroundImage; + backgroundRepeat = attrs->backgroundRepeat; + backgroundAttachment = attrs->backgroundAttachment; + backgroundPositionX = attrs->backgroundPositionX; + backgroundPositionY = attrs->backgroundPositionY; textAlign = attrs->textAlign; valign = attrs->valign; textAlignChar = attrs->textAlignChar; @@ -450,6 +500,210 @@ Tooltip *Tooltip::create (Layout *layout, const char *text) // ---------------------------------------------------------------------- +void StyleImage::StyleImgRenderer::setBuffer (core::Imgbuf *buffer, bool resize) +{ + 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. + // + // This "tiled" buffer is not used when 'background-repeat' has + // another value than 'repeat', for obvious reasons. Image + // buffers only "tiled" in one dimension (to optimize 'repeat-x' + // and 'repeat-y') are not supported. + + 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) +{ + 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 () +{ + // Nothing to do. +} + +void StyleImage::StyleImgRenderer::fatal () +{ + // Nothing to do. +} + +StyleImage::StyleImage () +{ + //printf ("new StyleImage %p\n", this); + + refCount = 0; + imgbufSrc = NULL; + imgbufTiled = NULL; + + imgRendererDist = new ImgRendererDist (); + styleImgRenderer = new StyleImgRenderer (this); + imgRendererDist->put (styleImgRenderer); +} + +StyleImage::~StyleImage () +{ + //printf ("delete StyleImage %p\n", this); + + if (imgbufSrc) + imgbufSrc->unref (); + if (imgbufTiled) + imgbufTiled->unref (); + + delete imgRendererDist; + delete styleImgRenderer; +} + +void StyleImage::ExternalImgRenderer::setBuffer (core::Imgbuf *buffer, + bool resize) +{ + // Nothing to do? +} + +void StyleImage::ExternalImgRenderer::drawRow (int row) +{ + if (drawBackgroundLineByLine) { + StyleImage *backgroundImage; + if (readyToDraw () && (backgroundImage = getBackgroundImage ())) { + // All single rows are drawn. + + Imgbuf *imgbuf = backgroundImage->getImgbufSrc(); + int imgWidth = imgbuf->getRootWidth (); + int imgHeight = imgbuf->getRootHeight (); + + int x, y, width, height; + getBgArea (&x, &y, &width, &height); + + int xRef, yRef, widthRef, heightRef; + getRefArea (&xRef, &yRef, &widthRef, &heightRef); + + bool repeatX, repeatY, doDraw; + int origX, origY, tileX1, tileX2, tileY1, tileY2; + + calcBackgroundRelatedValues (backgroundImage, + getBackgroundRepeat (), + getBackgroundAttachment (), + getBackgroundPositionX (), + getBackgroundPositionY (), + x, y, width, height, xRef, yRef, widthRef, + heightRef, &repeatX, &repeatY, &origX, + &origY, &tileX1, &tileX2, &tileY1, + &tileY2, &doDraw); + + //printf ("tileX1 = %d, tileX2 = %d, tileY1 = %d, tileY2 = %d\n", + // tileX1, tileX2, tileY1, tileY2); + + if (doDraw) + // Only iterate over y, because the rows can be combined + // horizontally. + for (int tileY = tileY1; tileY <= tileY2; tileY++) { + int x1 = misc::max (origX + tileX1 * imgWidth, x); + int x2 = misc::min (origX + (tileX2 + 1) * imgWidth, x + width); + + int yt = origY + tileY * imgHeight + row; + if (yt >= y && yt < y + height) + draw (x1, yt, x2 - x1, 1); + } + } + } +} + +void StyleImage::ExternalImgRenderer::finish () +{ + if (!drawBackgroundLineByLine) { + if (readyToDraw ()) { + // Draw total area, as a whole. + int x, y, width, height; + getBgArea (&x, &y, &width, &height); + draw (x, y, width, height); + } + } +} + +void StyleImage::ExternalImgRenderer::fatal () +{ + // Nothing to do. +} + +// ---------------------------------------------------------------------- + +StyleImage *StyleImage::ExternalWidgetImgRenderer::getBackgroundImage () +{ + Style *style = getStyle (); + return style ? style->backgroundImage : NULL; +} + +BackgroundRepeat StyleImage::ExternalWidgetImgRenderer::getBackgroundRepeat () +{ + Style *style = getStyle (); + return style ? style->backgroundRepeat : BACKGROUND_REPEAT; +} + +BackgroundAttachment + StyleImage::ExternalWidgetImgRenderer::getBackgroundAttachment () +{ + Style *style = getStyle (); + return style ? style->backgroundAttachment : BACKGROUND_ATTACHMENT_SCROLL; +} + +Length StyleImage::ExternalWidgetImgRenderer::getBackgroundPositionX () +{ + Style *style = getStyle (); + return style ? style->backgroundPositionX : createPerLength (0); +} + +Length StyleImage::ExternalWidgetImgRenderer::getBackgroundPositionY () +{ + Style *style = getStyle (); + return style ? style->backgroundPositionY : createPerLength (0); +} + +// ---------------------------------------------------------------------- + /* * The drawBorder{Top,Bottom,Left,Right} functions are similar. They * use a trapezium as draw polygon, or drawTypedLine() for dots and dashes. @@ -851,8 +1105,11 @@ static void drawBorderRight(View *view, Style *style, * \brief Draw the border of a region in window, according to style. * * Used by dw::core::Widget::drawBox and dw::core::Widget::drawWidgetBox. + * + * "area" is the area to be drawn, "x", "y", "width" and "height" + * define the box itself. All are given in canvas coordinates. */ -void drawBorder (View *view, Rectangle *area, +void drawBorder (View *view, Layout *layout, Rectangle *area, int x, int y, int width, int height, Style *style, bool inverse) { @@ -889,29 +1146,193 @@ void drawBorder (View *view, Rectangle *area, * according to style. * * Used by dw::core::Widget::drawBox and dw::core::Widget::drawWidgetBox. + * + * "area" is the area to be drawn, "x", "y", "width" and "height" + * define the box itself (padding box). "xRef", "yRef", "widthRef" and + * "heightRef" define the reference area, which is important for the + * tiling of background images (for position 0%/0%, a tile is set at + * xRef/yRef; for position 100%/100%, a tile is set at xRef + + * widthRef/yRef + widthRef). See calls for more informations; in most + * cases, these boxes are identical (padding box). All these + * coordinates are given in canvas coordinates. + * + * "atTop" should be true, only if the area is drawn directly on the + * canvas, not on top of other areas; this is only true for the + * toplevel widget itself (not parts of its contents). Toplevel widget + * background colors are already set as viewport background color, so + * that drawing again is is not neccessary, but some time can be + * saved. + * + * Otherwise, the caller should not try to increase the performance by + * doing some tests before; this is all done in this method. */ -void drawBackground (View *view, Rectangle *area, +void drawBackground (View *view, Layout *layout, Rectangle *area, int x, int y, int width, int height, - Style *style, bool inverse) -{ - Rectangle bgArea, intersection; - - if (style->backgroundColor) { - bgArea.x = x + style->margin.left + style->borderWidth.left; - bgArea.y = y + style->margin.top + style->borderWidth.top; - bgArea.width = - width - style->margin.left - style->borderWidth.left - - style->margin.right - style->borderWidth.right; - bgArea.height = - height - style->margin.top - style->borderWidth.top - - style->margin.bottom - style->borderWidth.bottom; - - if (area->intersectsWith (&bgArea, &intersection)) - view->drawRectangle (style->backgroundColor, - inverse ? - Color::SHADING_INVERSE : Color::SHADING_NORMAL, - true, intersection.x, intersection.y, - intersection.width, intersection.height); + int xRef, int yRef, int widthRef, int heightRef, + Style *style, bool inverse, bool atTop) +{ + bool bgColor = style->backgroundColor != NULL && + // The test for background colors is rather simple, since only the color + // has to be compared, ... + (!atTop || layout->getBgColor () != style->backgroundColor); + bool bgImage = (style->backgroundImage != 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 + // background image of the toplevel widget is set), only the background + // images are compared. A full test, which also deals with all other + // attributes related to background images (repeat, position etc.) would + // be complicated and useless, so not worth the work. + (!atTop || layout->getBgImage () != style->backgroundImage); + + // Since widgets are always drawn from top to bottom, it is *not* + // necessary to draw the background if background color and image + // are not set (NULL), i. e. shining through. + + if (bgColor || bgImage) { + Rectangle bgArea, intersection; + bgArea.x = x; + bgArea.y = y; + bgArea.width = width; + bgArea.height = height; + + if (area->intersectsWith (&bgArea, &intersection)) { + if (bgColor) + view->drawRectangle (style->backgroundColor, + inverse ? + Color::SHADING_INVERSE : Color::SHADING_NORMAL, + true, intersection.x, intersection.y, + intersection.width, intersection.height); + + if (bgImage) + drawBackgroundImage (view, style->backgroundImage, + style->backgroundRepeat, + style->backgroundAttachment, + style->backgroundPositionX, + style->backgroundPositionY, + intersection.x, intersection.y, + intersection.width, intersection.height, + xRef, yRef, widthRef, heightRef); + + } + } +} + +void drawBackgroundImage (View *view, StyleImage *backgroundImage, + BackgroundRepeat backgroundRepeat, + BackgroundAttachment backgroundAttachment, + Length backgroundPositionX, + Length backgroundPositionY, + int x, int y, int width, int height, + int xRef, int yRef, int widthRef, int heightRef) +{ + //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); + + bool repeatX, repeatY, doDraw; + int origX, origY, tileX1, tileX2, tileY1, tileY2; + + calcBackgroundRelatedValues (backgroundImage, backgroundRepeat, + backgroundAttachment, backgroundPositionX, + backgroundPositionY, x, y, width, height, + xRef, yRef, widthRef, heightRef, + &repeatX, &repeatY, &origX, &origY, + &tileX1, &tileX2, &tileY1, &tileY2, &doDraw); + + //printf ("tileX1 = %d, tileX2 = %d, tileY1 = %d, tileY2 = %d\n", + // tileX1, tileX2, tileY1, tileY2); + + 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(repeatX, repeatY); + int imgWidthT = imgbufT->getRootWidth (); + int imgHeightT = imgbufT->getRootHeight (); + int tilesX = backgroundImage->getTilesX (repeatX, repeatY); + int tilesY = backgroundImage->getTilesY (repeatX, repeatY); + + 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 + imgWidthT, x + width); + int yt = origY + tileY * imgHeightS; + int y1 = misc::max (yt, y); + int y2 = misc::min (yt + imgHeightT, y + height); + + view->drawImage (imgbufT, xt, yt, x1 - xt, y1 - yt, + x2 - x1, y2 - y1); + } + } +} + +void calcBackgroundRelatedValues (StyleImage *backgroundImage, + BackgroundRepeat backgroundRepeat, + BackgroundAttachment backgroundAttachment, + Length backgroundPositionX, + Length backgroundPositionY, + int xDraw, int yDraw, int widthDraw, + int heightDraw, int xRef, int yRef, + int widthRef, int heightRef, bool *repeatX, + bool *repeatY, int *origX, int *origY, + int *tileX1, int *tileX2, int *tileY1, + int *tileY2, bool *doDraw) +{ + Imgbuf *imgbuf = backgroundImage->getImgbufSrc(); + int imgWidth = imgbuf->getRootWidth (); + int imgHeight = imgbuf->getRootHeight (); + + *repeatX = backgroundRepeat == BACKGROUND_REPEAT || + backgroundRepeat == BACKGROUND_REPEAT_X; + *repeatY = backgroundRepeat == BACKGROUND_REPEAT || + backgroundRepeat == BACKGROUND_REPEAT_Y; + + *origX = xRef + + (isPerLength (backgroundPositionX) ? + multiplyWithPerLength (widthRef - imgWidth, backgroundPositionX) : + absLengthVal (backgroundPositionX)); + *origY = yRef + + (isPerLength (backgroundPositionY) ? + multiplyWithPerLength (heightRef - imgHeight, backgroundPositionY) : + absLengthVal (backgroundPositionY)); + + *tileX1 = xDraw < *origX ? + - (*origX - xDraw + imgWidth - 1) / imgWidth : + (xDraw - *origX) / imgWidth; + *tileX2 = *origX < xDraw + widthDraw ? + (xDraw + widthDraw - *origX - 1) / imgWidth : + - (*origX - (xDraw + widthDraw) + imgWidth - 1) / imgWidth; + *tileY1 = yDraw < *origY ? + - (*origY - yDraw + imgHeight - 1) / imgHeight : + (yDraw - *origY) / imgHeight; + *tileY2 = *origY < yDraw + heightDraw ? + (yDraw + heightDraw - *origY - 1) / imgHeight : + - (*origY - (yDraw + heightDraw) + imgHeight - 1) / imgHeight; + + *doDraw = true; + if (!*repeatX) { + // Only center tile (tileX = 0) is drawn, ... + if (*tileX1 <= 0 && *tileX2 >= 0) + // ... and is visible. + *tileX1 = *tileX2 = 0; + else + // ... but is not visible. + *doDraw = false; + } + + if (!*repeatY) { + // Analogue. + if (*tileY1 <= 0 && *tileY2 >= 0) + *tileY1 = *tileY2 = 0; + else + *doDraw = false; } } diff --git a/dw/style.hh b/dw/style.hh index 96343df9..3fe3b7c9 100644 --- a/dw/style.hh +++ b/dw/style.hh @@ -7,6 +7,8 @@ # error Do not include this file directly, use "core.hh" instead. #endif +#include "../lout/signal.hh" + namespace dw { namespace core { @@ -228,6 +230,18 @@ enum BorderStyle { BORDER_OUTSET }; +enum BackgroundRepeat { + BACKGROUND_REPEAT, + BACKGROUND_REPEAT_X, + BACKGROUND_REPEAT_Y, + BACKGROUND_NO_REPEAT +}; + +enum BackgroundAttachment { + BACKGROUND_ATTACHMENT_SCROLL, + BACKGROUND_ATTACHMENT_FIXED +}; + enum TextAlignType { TEXT_ALIGN_LEFT, TEXT_ALIGN_RIGHT, @@ -482,9 +496,10 @@ public: } }; +class Tooltip; class Font; class Color; -class Tooltip; +class StyleImage; /** * \sa dw::core::style @@ -496,6 +511,11 @@ public: int textDecoration; /* No TextDecoration because of problems converting * TextDecoration <-> int */ Color *color, *backgroundColor; + StyleImage *backgroundImage; + BackgroundRepeat backgroundRepeat; + BackgroundAttachment backgroundAttachment; + Length backgroundPositionX; // "left" defined by "0%" etc. (see CSS spec) + Length backgroundPositionY; // "top" defined by "0%" etc. (see CSS spec) TextAlignType textAlign; VAlignType valign; @@ -561,7 +581,8 @@ public: } inline int boxDiffHeight () { return boxOffsetY () + boxRestHeight (); } - inline bool hasBackground () { return backgroundColor != NULL; } + inline bool hasBackground () + { return backgroundColor != NULL || backgroundImage != NULL; } bool equals (lout::object::Object *other); int hashValue (); @@ -734,12 +755,139 @@ public: { if (--refCount == 0) delete this; } }; -void drawBorder (View *view, Rectangle *area, + +class StyleImage: public lout::signal::ObservedObject +{ +private: + class StyleImgRenderer: public ImgRenderer + { + private: + StyleImage *image; + + public: + inline StyleImgRenderer (StyleImage *image) { this->image = image; } + + void setBuffer (core::Imgbuf *buffer, bool resize); + void drawRow (int row); + void finish (); + void fatal (); + }; + + int refCount, tilesX, tilesY; + Imgbuf *imgbufSrc, *imgbufTiled; + ImgRendererDist *imgRendererDist; + StyleImgRenderer *styleImgRenderer; + + StyleImage (); + ~StyleImage (); + +public: + /** + * \brief Useful (but not mandatory) base class for updates of + * areas with background images. + */ + class ExternalImgRenderer: public ImgRenderer + { + public: + void setBuffer (core::Imgbuf *buffer, bool resize); + void drawRow (int row); + void finish (); + void fatal (); + + /** + * \brief If this method returns false, nothing is done at all. + */ + virtual bool readyToDraw () = 0; + + /** + * \brief Return the area covered by the background image. + */ + virtual void getBgArea (int *x, int *y, int *width, int *height) = 0; + + /** + * \brief Return the "reference area". + * + * See comment of "drawBackground". + */ + virtual void getRefArea (int *xRef, int *yRef, int *widthRef, + int *heightRef) = 0; + + virtual StyleImage *getBackgroundImage () = 0; + virtual BackgroundRepeat getBackgroundRepeat () = 0; + virtual BackgroundAttachment getBackgroundAttachment () = 0; + virtual Length getBackgroundPositionX () = 0; + virtual Length getBackgroundPositionY () = 0; + + /** + * \brief Draw (or queue for drawing) an area, which is given in + * canvas coordinates. + */ + virtual void draw (int x, int y, int width, int height) = 0; + }; + + /** + * \brief Suitable for widgets and parts of widgets. + */ + class ExternalWidgetImgRenderer: public ExternalImgRenderer + { + public: + void getPaddingArea (int *x, int *y, int *width, int *height); + + StyleImage *getBackgroundImage (); + BackgroundRepeat getBackgroundRepeat (); + BackgroundAttachment getBackgroundAttachment (); + Length getBackgroundPositionX (); + Length getBackgroundPositionY (); + + /** + * \brief Return the style this background image is part of. + */ + virtual Style *getStyle () = 0; + }; + + static StyleImage *create () { return new StyleImage (); } + + inline void ref () { refCount++; } + inline void unref () + { if (--refCount == 0) delete this; } + + inline Imgbuf *getImgbufSrc () { return imgbufSrc; } + inline Imgbuf *getImgbufTiled (bool repeatX, bool repeatY) + { return (imgbufTiled && repeatX && repeatY) ? imgbufTiled : imgbufSrc; } + inline int getTilesX (bool repeatX, bool repeatY) + { return (imgbufTiled && repeatX && repeatY) ? tilesX : 1; } + inline int getTilesY (bool repeatX, bool repeatY) + { return (imgbufTiled && repeatX && repeatY) ? tilesY : 1; } + inline ImgRenderer *getMainImgRenderer () { return imgRendererDist; } + + /** + * \brief Add an additional ImgRenderer, especially used for + * drawing. + */ + inline void putExternalImgRenderer (ImgRenderer *ir) + { imgRendererDist->put (ir); } + + /** + * \brief Remove a previously added additional ImgRenderer. + */ + inline void removeExternalImgRenderer (ImgRenderer *ir) + { imgRendererDist->remove (ir); } +}; + +void drawBorder (View *view, Layout *layout, Rectangle *area, int x, int y, int width, int height, Style *style, bool inverse); -void drawBackground (View *view, Rectangle *area, +void drawBackground (View *view, Layout *layout, Rectangle *area, int x, int y, int width, int height, - Style *style, bool inverse); + int xRef, int yRef, int widthRef, int heightRef, + Style *style, bool inverse, bool atTop); +void drawBackgroundImage (View *view, StyleImage *backgroundImage, + BackgroundRepeat backgroundRepeat, + BackgroundAttachment backgroundAttachment, + Length backgroundPositionX, + Length backgroundPositionY, + int x, int y, int width, int height, + int xRef, int yRef, int widthRef, int heightRef); void numtostr (int num, char *buf, int buflen, ListStyleType listStyleType); } // namespace style diff --git a/dw/table.cc b/dw/table.cc index f1a9c5c1..eef1b6ce 100644 --- a/dw/table.cc +++ b/dw/table.cc @@ -22,6 +22,7 @@ #include "table.hh" #include "../lout/msg.h" #include "../lout/misc.hh" +#include "../lout/debug.hh" using namespace lout; @@ -31,6 +32,7 @@ int Table::CLASS_ID = -1; Table::Table(bool limitTextWidth) { + DBG_OBJ_CREATE ("dw::Table"); registerName ("dw::Table", &CLASS_ID); setFlags (BLOCK_LEVEL); setFlags (USES_HINTS); diff --git a/dw/tablecell.cc b/dw/tablecell.cc index 66f86576..edad1524 100644 --- a/dw/tablecell.cc +++ b/dw/tablecell.cc @@ -20,6 +20,7 @@ #include "tablecell.hh" +#include "../lout/debug.hh" #include <stdio.h> namespace dw { @@ -29,6 +30,7 @@ int TableCell::CLASS_ID = -1; TableCell::TableCell (TableCell *ref, bool limitTextWidth): AlignedTextblock (limitTextWidth) { + DBG_OBJ_CREATE ("dw::TableCell"); registerName ("dw::TableCell", &CLASS_ID); /** \bug ignoreLine1OffsetSometimes does not work? */ diff --git a/dw/textblock.cc b/dw/textblock.cc index b4f5c3d4..c0a902f4 100644 --- a/dw/textblock.cc +++ b/dw/textblock.cc @@ -22,6 +22,7 @@ #include "../lout/msg.h" #include "../lout/misc.hh" #include "../lout/unicode.hh" +#include "../lout/debug.hh" #include <stdio.h> #include <math.h> // remove again? @@ -42,6 +43,103 @@ namespace dw { int Textblock::CLASS_ID = -1; +Textblock::WordImgRenderer::WordImgRenderer (Textblock *textblock, + int wordNo) +{ + //printf ("new WordImgRenderer %p\n", this); + + this->textblock = textblock; + this->wordNo = wordNo; + dataSet = false; +} + +Textblock::WordImgRenderer::~WordImgRenderer () +{ + //printf ("delete WordImgRenderer %p\n", this); +} + +void Textblock::WordImgRenderer::setData (int xWordWidget, int lineNo) +{ + dataSet = true; + this->xWordWidget = xWordWidget; + this->lineNo = lineNo; +} + +bool Textblock::WordImgRenderer::readyToDraw () +{ + //print (); + //printf ("\n"); + + return dataSet && textblock->wasAllocated () + && wordNo < textblock->words->size() + && lineNo < textblock->lines->size(); +} + +void Textblock::WordImgRenderer::getBgArea (int *x, int *y, int *width, + int *height) +{ + // TODO Subtract margin and border (padding box)? + Line *line = textblock->lines->getRef (lineNo); + *x = textblock->allocation.x + this->xWordWidget; + *y = textblock->lineYOffsetCanvas (line); + *width = textblock->words->getRef(wordNo)->size.width; + *height = line->boxAscent + line->boxDescent; +} + +void Textblock::WordImgRenderer::getRefArea (int *xRef, int *yRef, + int *widthRef, int *heightRef) +{ + // See comment in Widget::drawBox about the reference area. + textblock->getPaddingArea (xRef, yRef, widthRef, heightRef); +} + +core::style::Style *Textblock::WordImgRenderer::getStyle () +{ + return textblock->words->getRef(wordNo)->style; +} + +void Textblock::WordImgRenderer::draw (int x, int y, int width, int height) +{ + textblock->queueDrawArea (x - textblock->allocation.x, + y - textblock->allocation.y, width, height); + +} + +void Textblock::WordImgRenderer::print () +{ + printf ("%p: word #%d, ", this, wordNo); + if (wordNo < textblock->words->size()) + textblock->printWordShort (textblock->words->getRef(wordNo)); + else + printf ("<word %d does not exist>", wordNo); + printf (", data set: %s", dataSet ? "yes" : "no"); +} + +void Textblock::SpaceImgRenderer::getBgArea (int *x, int *y, int *width, + int *height) +{ + WordImgRenderer::getBgArea (x, y, width, height); + *x += *width; + *width = textblock->words->getRef(wordNo)->effSpace; +} + +core::style::Style *Textblock::SpaceImgRenderer::getStyle () +{ + return textblock->words->getRef(wordNo)->spaceStyle; +} + +void Textblock::SpaceImgRenderer::print () +{ + printf ("%p: word FOR SPACE #%d, ", this, wordNo); + if (wordNo < textblock->words->size()) + textblock->printWordShort (textblock->words->getRef(wordNo)); + else + printf ("<word %d does not exist>", wordNo); + printf (", data set: %s", dataSet ? "yes" : "no"); +} + +// ---------------------------------------------------------------------- + Textblock::DivChar Textblock::divChars[NUM_DIV_CHARS] = { // soft hyphen (U+00AD) { "\xc2\xad", true, false, true, PENALTY_HYPHEN, -1 }, @@ -125,6 +223,7 @@ void Textblock::setStretchabilityFactor (int stretchabilityFactor) Textblock::Textblock (bool limitTextWidth) { + DBG_OBJ_CREATE ("dw::Textblock"); registerName ("dw::Textblock", &CLASS_ID); setFlags (BLOCK_LEVEL); setFlags (USES_HINTS); @@ -195,9 +294,14 @@ Textblock::~Textblock () for (int i = 0; i < words->size(); i++) { Word *word = words->getRef (i); + if (word->content.type == core::Content::WIDGET_IN_FLOW) delete word->content.widget; /** \todo Widget references? What about texts? */ + + removeWordImgRenderer (i); + removeSpaceImgRenderer (i); + word->style->unref (); word->spaceStyle->unref (); } @@ -1528,14 +1632,77 @@ Textblock::Word *Textblock::addWord (int width, int ascent, int descent, short flags, core::style::Style *style) { words->increase (); - Word *word = words->getLastRef (); - fillWord (word, width, ascent, descent, flags, style); - return word; + int wordNo = words->size () - 1; + initWord (wordNo); + fillWord (wordNo, width, ascent, descent, flags, style); + return words->getRef (wordNo);; +} + +/** + * Basic initialization, which is neccessary before fillWord. + */ +void Textblock::initWord (int wordNo) +{ + Word *word = words->getRef (wordNo); + + word->style = word->spaceStyle = NULL; + word->wordImgRenderer = NULL; + word->spaceImgRenderer = NULL; +} + +void Textblock::removeWordImgRenderer (int wordNo) +{ + Word *word = words->getRef (wordNo); + + if (word->style && word->wordImgRenderer) { + word->style->backgroundImage->removeExternalImgRenderer + (word->wordImgRenderer); + delete word->wordImgRenderer; + word->wordImgRenderer = NULL; + } +} + +void Textblock::setWordImgRenderer (int wordNo) +{ + Word *word = words->getRef (wordNo); + + if (word->style->backgroundImage) { + word->wordImgRenderer = new WordImgRenderer (this, wordNo); + word->style->backgroundImage->putExternalImgRenderer + (word->wordImgRenderer); + } else + word->wordImgRenderer = NULL; +} + +void Textblock::removeSpaceImgRenderer (int wordNo) +{ + Word *word = words->getRef (wordNo); + + if (word->spaceStyle && word->spaceImgRenderer) { + word->spaceStyle->backgroundImage->removeExternalImgRenderer + (word->spaceImgRenderer); + delete word->spaceImgRenderer; + word->spaceImgRenderer = NULL; + } +} + +void Textblock::setSpaceImgRenderer (int wordNo) +{ + Word *word = words->getRef (wordNo); + + if (word->spaceStyle->backgroundImage) { + word->spaceImgRenderer = new SpaceImgRenderer (this, wordNo); + word->spaceStyle->backgroundImage->putExternalImgRenderer + (word->spaceImgRenderer); + } else + word->spaceImgRenderer = NULL; } -void Textblock::fillWord (Word *word, int width, int ascent, int descent, +void Textblock::fillWord (int wordNo, int width, int ascent, int descent, short flags, core::style::Style *style) { + Word *word = words->getRef (wordNo); + word->size.width = width; word->size.ascent = ascent; word->size.descent = descent; @@ -1545,8 +1712,15 @@ void Textblock::fillWord (Word *word, int width, int ascent, int descent, word->content.space = false; word->flags = flags; + removeWordImgRenderer (wordNo); + removeSpaceImgRenderer (wordNo); + word->style = style; word->spaceStyle = style; + + setWordImgRenderer (wordNo); + setSpaceImgRenderer (wordNo); + style->ref (); style->ref (); } @@ -1622,8 +1796,6 @@ void Textblock::calcTextSize (const char *text, size_t len, core::style::Style *style, core::Requisition *size, bool isStart, bool isEnd) { - int requiredAscent, requiredDescent; - size->width = textWidth (text, 0, len, style, isStart, isEnd); size->ascent = style->font->ascent; size->descent = style->font->descent; @@ -1663,10 +1835,10 @@ void Textblock::calcTextSize (const char *text, size_t len, * potentially the line's height. */ if (style->valign == core::style::VALIGN_SUB) { - requiredDescent = style->font->descent + style->font->ascent / 3; + int requiredDescent = style->font->descent + style->font->ascent / 3; size->descent = misc::max (size->descent, requiredDescent); } else if (style->valign == core::style::VALIGN_SUPER) { - requiredAscent = style->font->ascent + style->font->ascent / 2; + int requiredAscent = style->font->ascent + style->font->ascent / 2; size->ascent = misc::max (size->ascent, requiredAscent); } } @@ -2052,7 +2224,7 @@ void Textblock::addSpace (core::style::Style *style) { int wordIndex = words->size () - 1; if (wordIndex >= 0) { - fillSpace (words->getRef(wordIndex), style); + fillSpace (wordIndex, style); accumulateWordData (wordIndex); correctLastWordExtremes (); } @@ -2074,7 +2246,7 @@ void Textblock::addBreakOption (core::style::Style *style, bool forceBreak) } } -void Textblock::fillSpace (Word *word, core::style::Style *style) +void Textblock::fillSpace (int wordNo, core::style::Style *style) { // Old comment: // @@ -2090,6 +2262,8 @@ void Textblock::fillSpace (Word *word, core::style::Style *style) // // TODO: Re-evaluate again. + Word *word = words->getRef (wordNo); + // TODO: This line does not work: addBreakOption (word, style); if (// Do not override a previously set break penalty: @@ -2109,9 +2283,14 @@ void Textblock::fillSpace (Word *word, core::style::Style *style) //DBG_OBJ_ARRSET_NUM (this, "words.%d.content.space", wordIndex, // word->content.space); + + removeSpaceImgRenderer (wordNo); + word->spaceStyle->unref (); word->spaceStyle = style; style->ref (); + + setSpaceImgRenderer (wordNo); } } diff --git a/dw/textblock.hh b/dw/textblock.hh index 3af933ce..b9255bb9 100644 --- a/dw/textblock.hh +++ b/dw/textblock.hh @@ -244,6 +244,44 @@ private: OutOfFlowMgr *outOfFlowMgr; protected: + /** + * \brief Implementation used for words. + */ + class WordImgRenderer: + public core::style::StyleImage::ExternalWidgetImgRenderer + { + protected: + Textblock *textblock; + int wordNo, xWordWidget, lineNo; + bool dataSet; + + public: + WordImgRenderer (Textblock *textblock, int wordNo); + ~WordImgRenderer (); + + void setData (int xWordWidget, int lineNo); + + bool readyToDraw (); + void getBgArea (int *x, int *y, int *width, int *height); + void getRefArea (int *xRef, int *yRef, int *widthRef, int *heightRef); + core::style::Style *getStyle (); + void draw (int x, int y, int width, int height); + + virtual void print (); + }; + + class SpaceImgRenderer: public WordImgRenderer + { + public: + inline SpaceImgRenderer (Textblock *textblock, int wordNo) : + WordImgRenderer (textblock, wordNo) { } + + void getBgArea (int *x, int *y, int *width, int *height); + core::style::Style *getStyle (); + + void print (); + }; + struct Paragraph { int firstWord; /* first word's index in word vector */ @@ -373,6 +411,11 @@ protected: core::style::Style *style; core::style::Style *spaceStyle; /* initially the same as of the word, later set by a_Dw_page_add_space */ + + // These two are used rarely, so there is perhaps a way to store + // them which is consuming less memory. + WordImgRenderer *wordImgRenderer; + SpaceImgRenderer *spaceImgRenderer; }; void printWordShort (Word *word); @@ -536,9 +579,14 @@ protected: Word *addWord (int width, int ascent, int descent, short flags, core::style::Style *style); - void fillWord (Word *word, int width, int ascent, int descent, + void initWord (int wordNo); + void removeWordImgRenderer (int wordNo); + void setWordImgRenderer (int wordNo); + void removeSpaceImgRenderer (int wordNo); + void setSpaceImgRenderer (int wordNo); + void fillWord (int wordNo, int width, int ascent, int descent, short flags, core::style::Style *style); - void fillSpace (Word *word, core::style::Style *style); + void fillSpace (int wordNo, core::style::Style *style); void setBreakOption (Word *word, core::style::Style *style, int breakPenalty1, int breakPenalty2, bool forceBreak); bool isBreakAllowed (Word *word); diff --git a/dw/textblock_linebreaking.cc b/dw/textblock_linebreaking.cc index 6d3e3f39..1c1a3c1f 100644 --- a/dw/textblock_linebreaking.cc +++ b/dw/textblock_linebreaking.cc @@ -432,6 +432,16 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord, //printf (": "); //words->getRef(line->lastWord)->badnessAndPenalty.print (); //printf ("\n"); + + int xWidget = line->offsetCompleteWidget; + for (int i = firstWord; i <= lastWord; i++) { + Word *word = words->getRef (i); + if (word->wordImgRenderer) + word->wordImgRenderer->setData (xWidget, lines->size () - 1); + if (word->spaceImgRenderer) + word->spaceImgRenderer->setData (xWidget, lines->size () - 1); + xWidget += word->size.width + word->effSpace; + } line->finished = true; @@ -1026,6 +1036,8 @@ int Textblock::hyphenateWord (int wordIndex) PRINTF ("[%p] %d words ...\n", this, words->size ()); words->insert (wordIndex, numBreaks); + for (int i = 0; i < numBreaks; i++) + initWord (wordIndex + i); PRINTF ("[%p] ... => %d words\n", this, words->size ()); if (containingBlock->outOfFlowMgr) @@ -1041,8 +1053,7 @@ int Textblock::hyphenateWord (int wordIndex) for (int i = 0; i < numBreaks + 1; i++) { Word *w = words->getRef (wordIndex + i); - - fillWord (w, wordSize[i].width, wordSize[i].ascent, + fillWord (wordIndex + i, wordSize[i].width, wordSize[i].ascent, wordSize[i].descent, false, origWord.style); // TODO There should be a method fillText0. @@ -1081,7 +1092,7 @@ int Textblock::hyphenateWord (int wordIndex) PRINTF (" [%d] + hyphen\n", wordIndex + i); } else { if (origWord.content.space) { - fillSpace (w, origWord.spaceStyle); + fillSpace (wordIndex + i, origWord.spaceStyle); PRINTF (" [%d] + space\n", wordIndex + i); } else { PRINTF (" [%d] + nothing\n", wordIndex + i); @@ -20,6 +20,7 @@ #include "core.hh" +#include "../lout/debug.hh" #include <stdio.h> @@ -34,6 +35,7 @@ int Embed::CLASS_ID = -1; Embed::Embed(Resource *resource) { + DBG_OBJ_CREATE ("dw::core::ui::Embed"); registerName ("dw::core::ui::Embed", &CLASS_ID); this->resource = resource; resource->setEmbed (this); diff --git a/dw/widget.cc b/dw/widget.cc index f1f47f9e..83b9956a 100644 --- a/dw/widget.cc +++ b/dw/widget.cc @@ -32,10 +32,41 @@ namespace core { // ---------------------------------------------------------------------- +bool Widget::WidgetImgRenderer::readyToDraw () +{ + return widget->wasAllocated (); +} + +void Widget::WidgetImgRenderer::getBgArea (int *x, int *y, int *width, + int *height) +{ + widget->getPaddingArea (x, y, width, height); +} + +void Widget::WidgetImgRenderer::getRefArea (int *xRef, int *yRef, int *widthRef, + int *heightRef) +{ + widget->getPaddingArea (xRef, yRef, widthRef, heightRef); +} + +style::Style *Widget::WidgetImgRenderer::getStyle () +{ + return widget->getStyle (); +} + +void Widget::WidgetImgRenderer::draw (int x, int y, int width, int height) +{ + widget->queueDrawArea (x - widget->allocation.x, y - widget->allocation.y, + width, height); +} + +// ---------------------------------------------------------------------- + int Widget::CLASS_ID = -1; Widget::Widget () { + DBG_OBJ_CREATE ("dw::core::Widget"); registerName ("dw::core::Widget", &CLASS_ID); flags = (Flags)(NEEDS_RESIZE | EXTREMES_CHANGED | HAS_CONTENTS); @@ -55,6 +86,8 @@ Widget::Widget () deleteCallbackData = NULL; deleteCallbackFunc = NULL; + + widgetImgRenderer = NULL; } Widget::~Widget () @@ -62,6 +95,12 @@ Widget::~Widget () if (deleteCallbackFunc) deleteCallbackFunc (deleteCallbackData); + if (widgetImgRenderer) { + if (style && style->backgroundImage) + style->backgroundImage->removeExternalImgRenderer (widgetImgRenderer); + delete widgetImgRenderer; + } + if (style) style->unref (); @@ -108,11 +147,11 @@ void Widget::setParent (Widget *parent) if (!buttonSensitiveSet) buttonSensitive = parent->buttonSensitive; - notifySetParent(); - - //DBG_OBJ_ASSOC (widget, parent); + DBG_OBJ_ASSOC_PARENT (parent); //printf ("The %s %p becomes a child of the %s %p\n", // getClassName(), this, parent->getClassName(), parent); + + notifySetParent(); } void Widget::queueDrawArea (int x, int y, int width, int height) @@ -220,9 +259,9 @@ void Widget::sizeRequest (Requisition *requisition) this->requisition = *requisition; unsetFlags (NEEDS_RESIZE); - DBG_OBJ_SET_NUM (this, "requisition->width", requisition->width); - DBG_OBJ_SET_NUM (this, "requisition->ascent", requisition->ascent); - DBG_OBJ_SET_NUM (this, "requisition->descent", requisition->descent); + DBG_OBJ_SET_NUM ("requisition.width", requisition->width); + DBG_OBJ_SET_NUM ("requisition.ascent", requisition->ascent); + DBG_OBJ_SET_NUM ("requisition.descent", requisition->descent); } else *requisition = this->requisition; @@ -255,8 +294,8 @@ void Widget::getExtremes (Extremes *extremes) this->extremes = *extremes; unsetFlags (EXTREMES_CHANGED); - DBG_OBJ_SET_NUM (this, "extremes->minWidth", extremes->minWidth); - DBG_OBJ_SET_NUM (this, "extremes->maxWidth", extremes->maxWidth); + DBG_OBJ_SET_NUM ("extremes.minWidth", extremes->minWidth); + DBG_OBJ_SET_NUM ("extremes.maxWidth", extremes->maxWidth); } else *extremes = this->extremes; @@ -318,11 +357,11 @@ void Widget::sizeAllocate (Allocation *allocation) resizeDrawImpl (); - DBG_OBJ_SET_NUM (this, "allocation.x", this->allocation.x); - DBG_OBJ_SET_NUM (this, "allocation.y", this->allocation.y); - DBG_OBJ_SET_NUM (this, "allocation.width", this->allocation.width); - DBG_OBJ_SET_NUM (this, "allocation.ascent", this->allocation.ascent); - DBG_OBJ_SET_NUM (this, "allocation.descent", this->allocation.descent); + DBG_OBJ_SET_NUM ("allocation.x", this->allocation.x); + DBG_OBJ_SET_NUM ("allocation.y", this->allocation.y); + DBG_OBJ_SET_NUM ("allocation.width", this->allocation.width); + DBG_OBJ_SET_NUM ("allocation.ascent", this->allocation.ascent); + DBG_OBJ_SET_NUM ("allocation.descent", this->allocation.descent); } /*unsetFlags (NEEDS_RESIZE);*/ @@ -366,6 +405,10 @@ void Widget::setStyle (style::Style *style) { bool sizeChanged; + if (widgetImgRenderer && this->style && this->style->backgroundImage) + this->style->backgroundImage->removeExternalImgRenderer + (widgetImgRenderer); + style->ref (); if (this->style) { @@ -376,6 +419,15 @@ void Widget::setStyle (style::Style *style) this->style = style; + if (style && style->backgroundImage) { + // Create instance of WidgetImgRenderer when needed. Until this + // widget is deleted, "widgetImgRenderer" will be kept, since it + // is not specific to the style, but only to this widget. + if (widgetImgRenderer == NULL) + widgetImgRenderer = new WidgetImgRenderer (this); + style->backgroundImage->putExternalImgRenderer (widgetImgRenderer); + } + if (layout != NULL) { layout->updateCursor (); } @@ -425,20 +477,31 @@ style::Color *Widget::getBgColor () void Widget::drawBox (View *view, style::Style *style, Rectangle *area, int x, int y, int width, int height, bool inverse) { - Rectangle viewArea; - viewArea.x = area->x + allocation.x; - viewArea.y = area->y + allocation.y; - viewArea.width = area->width; - viewArea.height = area->height; + Rectangle canvasArea; + canvasArea.x = area->x + allocation.x; + canvasArea.y = area->y + allocation.y; + canvasArea.width = area->width; + canvasArea.height = area->height; - style::drawBorder (view, &viewArea, allocation.x + x, allocation.y + y, + style::drawBorder (view, layout, &canvasArea, + allocation.x + x, allocation.y + y, width, height, style, inverse); - /** \todo Background images? */ - if (style->backgroundColor) - style::drawBackground (view, &viewArea, - allocation.x + x, allocation.y + y, width, height, - style, inverse); + // This method is used for inline elements, where the CSS 2 specification + // does not define what here is called "reference area". To make it look + // smoothly, the widget padding box is used. + + int xPad, yPad, widthPad, heightPad; + getPaddingArea (&xPad, &yPad, &widthPad, &heightPad); + style::drawBackground + (view, layout, &canvasArea, + allocation.x + x + style->margin.left + style->borderWidth.left, + allocation.y + y + style->margin.top + style->borderWidth.top, + width - style->margin.left - style->borderWidth.left + - style->margin.right - style->borderWidth.right, + height - style->margin.top - style->borderWidth.top + - style->margin.bottom - style->borderWidth.bottom, + xPad, yPad, widthPad, heightPad, style, inverse, false); } /** @@ -449,32 +512,21 @@ void Widget::drawBox (View *view, style::Style *style, Rectangle *area, */ void Widget::drawWidgetBox (View *view, Rectangle *area, bool inverse) { - Rectangle viewArea; - viewArea.x = area->x + allocation.x; - viewArea.y = area->y + allocation.y; - viewArea.width = area->width; - viewArea.height = area->height; + Rectangle canvasArea; + canvasArea.x = area->x + allocation.x; + canvasArea.y = area->y + allocation.y; + canvasArea.width = area->width; + canvasArea.height = area->height; - style::drawBorder (view, &viewArea, allocation.x, allocation.y, + style::drawBorder (view, layout, &canvasArea, allocation.x, allocation.y, allocation.width, getHeight (), style, inverse); - /** \todo Adjust following comment from the old dw sources. */ - /* - * - Toplevel widget background colors are set as viewport - * background color. This is not crucial for the rendering, but - * looks a bit nicer when scrolling. Furthermore, the viewport - * does anything else in this case. - * - * - Since widgets are always drawn from top to bottom, it is - * *not* necessary to draw the background if - * widget->style->background_color is NULL (shining through). - */ - /** \todo Background images? */ - - if (style->backgroundColor && - (parent || layout->getBgColor () != style->backgroundColor)) - style::drawBackground (view, &viewArea, allocation.x, allocation.y, - allocation.width, getHeight (), style, inverse); + int xPad, yPad, widthPad, heightPad; + getPaddingArea (&xPad, &yPad, &widthPad, &heightPad); + style::drawBackground (view, layout, &canvasArea, + xPad, yPad, widthPad, heightPad, + xPad, yPad, widthPad, heightPad, + style, inverse, parent == NULL); } /* @@ -639,6 +691,23 @@ void Widget::scrollTo (HPosition hpos, VPosition vpos, x + allocation.x, y + allocation.y, width, height); } +/** + * \brief Return the padding area (content plus padding). + * + * Used as "reference area" (ee comment of "style::drawBackground") + * for backgrounds. + */ +void Widget::getPaddingArea (int *xPad, int *yPad, int *widthPad, + int *heightPad) +{ + *xPad = allocation.x + style->margin.left + style->borderWidth.left; + *yPad = allocation.y + style->margin.top + style->borderWidth.top; + *widthPad = allocation.width - style->margin.left - style->borderWidth.left + - style->margin.right - style->borderWidth.right; + *heightPad = getHeight () - style->margin.top - style->borderWidth.top + - style->margin.bottom - style->borderWidth.bottom; +} + void Widget::getExtremesImpl (Extremes *extremes) { /* Simply return the requisition width */ diff --git a/dw/widget.hh b/dw/widget.hh index 7dd12267..c9aeb427 100644 --- a/dw/widget.hh +++ b/dw/widget.hh @@ -97,6 +97,28 @@ protected: BLOCK_LEVEL = 1 << 9, }; + /** + * \brief Implementation which represents the whole widget. + * + * The only instance is set created needed. + */ + class WidgetImgRenderer: public style::StyleImage::ExternalWidgetImgRenderer + { + private: + Widget *widget; + + public: + inline WidgetImgRenderer (Widget *widget) { this->widget = widget; } + + bool readyToDraw (); + void getBgArea (int *x, int *y, int *width, int *height); + void getRefArea (int *xRef, int *yRef, int *widthRef, int *heightRef); + style::Style *getStyle (); + void draw (int x, int y, int width, int height); + }; + + WidgetImgRenderer *widgetImgRenderer; + private: /** * \brief The parent widget, NULL for top-level widgets. @@ -351,6 +373,8 @@ public: void scrollTo (HPosition hpos, VPosition vpos, int x, int y, int width, int height); + void getPaddingArea (int *xPad, int *yPad, int *widthPad, int *heightPad); + /** * \brief Return an iterator for this widget. * |