aboutsummaryrefslogtreecommitdiff
path: root/dw
diff options
context:
space:
mode:
Diffstat (limited to 'dw')
-rw-r--r--dw/Makefile.am2
-rw-r--r--dw/core.hh1
-rw-r--r--dw/fltkimgbuf.cc31
-rw-r--r--dw/fltkimgbuf.hh3
-rw-r--r--dw/image.cc10
-rw-r--r--dw/image.hh5
-rw-r--r--dw/imgbuf.hh13
-rw-r--r--dw/imgrenderer.cc48
-rw-r--r--dw/imgrenderer.hh87
-rw-r--r--dw/layout.cc118
-rw-r--r--dw/layout.hh31
-rw-r--r--dw/style.cc465
-rw-r--r--dw/style.hh194
-rw-r--r--dw/table.cc132
-rw-r--r--dw/table.hh4
-rw-r--r--dw/textblock.cc208
-rw-r--r--dw/textblock.hh52
-rw-r--r--dw/textblock_linebreaking.cc21
-rw-r--r--dw/widget.cc136
-rw-r--r--dw/widget.hh24
20 files changed, 1442 insertions, 143 deletions
diff --git a/dw/Makefile.am b/dw/Makefile.am
index e108da60..d0d56d2a 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/core.hh b/dw/core.hh
index f39c38cc..022574b1 100644
--- a/dw/core.hh
+++ b/dw/core.hh
@@ -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/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/image.cc b/dw/image.cc
index 1cb9ce39..acb2779e 100644
--- a/dw/image.cc
+++ b/dw/image.cc
@@ -450,6 +450,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 3f493d8a..89361881 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)
{
}
@@ -189,6 +248,7 @@ Layout::Layout (Platform *platform)
DBG_OBJ_CREATE (this, "DwRenderLayout");
bgColor = NULL;
+ bgImage = NULL;
cursor = style::CURSOR_DEFAULT;
canvasWidth = canvasAscent = canvasDescent = 0;
@@ -216,18 +276,28 @@ Layout::Layout (Platform *platform)
platform->setLayout (this);
selectionState.setLayout(this);
+
+ 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;
@@ -508,6 +578,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;
@@ -650,6 +737,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 ()
{
//static int calls = 0;
diff --git a/dw/layout.hh b/dw/layout.hh
index 51d764a4..47554b42 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.
@@ -135,6 +156,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;
@@ -386,8 +412,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/style.cc b/dw/style.cc
index 6c0abda2..4ab5673a 100644
--- a/dw/style.cc
+++ b/dw/style.cc
@@ -34,6 +34,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;
@@ -48,6 +69,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;
textIndent = 0;
margin.setVal (0);
@@ -76,6 +102,11 @@ void StyleAttrs::resetValues ()
valign = VALIGN_BASELINE;
textAlignChar = '.';
backgroundColor = NULL;
+ backgroundImage = NULL;
+ backgroundRepeat = BACKGROUND_REPEAT;
+ backgroundAttachment = BACKGROUND_ATTACHMENT_SCROLL;
+ backgroundPositionX = createPerLength (0);
+ backgroundPositionY = createPerLength (0);
width = LENGTH_AUTO;
height = LENGTH_AUTO;
@@ -116,6 +147,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 &&
@@ -156,6 +192,11 @@ int StyleAttrs::hashValue () {
textDecoration +
(intptr_t) color +
(intptr_t) backgroundColor +
+ (intptr_t) backgroundImage +
+ backgroundRepeat +
+ backgroundAttachment +
+ backgroundPositionX +
+ backgroundPositionY +
textAlign +
valign +
textAlignChar +
@@ -205,6 +246,8 @@ Style::Style (StyleAttrs *attrs)
color->ref ();
if (backgroundColor)
backgroundColor->ref ();
+ if (backgroundImage)
+ backgroundImage->ref ();
if (borderColor.top)
borderColor.top->ref();
if (borderColor.bottom)
@@ -227,6 +270,8 @@ Style::~Style ()
color->unref ();
if (backgroundColor)
backgroundColor->unref ();
+ if (backgroundImage)
+ backgroundImage->unref ();
if (borderColor.top)
borderColor.top->unref();
if (borderColor.bottom)
@@ -248,6 +293,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;
@@ -422,6 +472,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.
@@ -823,8 +1077,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)
{
@@ -861,29 +1118,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 7c00ac1f..089cf59b 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,
@@ -396,12 +410,44 @@ inline bool isRelLength(Length l) { return (l & 3) == 3; }
/** \brief Returns the value of a length in pixels, as an integer. */
inline int absLengthVal(Length l) { return l >> 2; }
-/** \brief Returns the value of a percentage, relative to 1, as a double. */
+/** \brief Returns the value of a percentage, relative to 1, as a double.
+ *
+ * When possible, do not use this function directly; it may be removed
+ * soon. Instead, use multiplyWithPerLength or multiplyWithPerLengthRounded.
+ */
inline double perLengthVal(Length l) { return (double)(l & ~3) / (1 << 18); }
-/** \brief Returns the value of a relative length, as a float. */
+/** \brief Returns the value of a relative length, as a float.
+ *
+ * When possible, do not use this function directly; it may be removed
+ * soon.
+ */
inline double relLengthVal(Length l) { return (double)(l & ~3) / (1 << 18); }
+/**
+ * \brief Multiply an int with a percentage length, returning int.
+ *
+ * Use this instead of perLengthVal, when possible.
+ */
+inline int multiplyWithPerLength(int x, Length l) {
+ return x * perLengthVal(l);
+}
+
+/**
+ * \brief Like multiplyWithPerLength, but rounds to nearest integer
+ * instead of down.
+ *
+ * (This function exists for backward compatibility.)
+ */
+inline int multiplyWithPerLengthRounded (int x, Length l) {
+ return lout::misc::roundInt (x * perLengthVal(l));
+}
+
+inline int multiplyWithRelLength(int x, Length l) {
+ return x * relLengthVal(l);
+}
+
+
enum {
/** \brief Represents "auto" lengths. */
LENGTH_AUTO = 0
@@ -431,9 +477,10 @@ public:
}
};
+class Tooltip;
class Font;
class Color;
-class Tooltip;
+class StyleImage;
/**
* \sa dw::core::style
@@ -445,6 +492,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;
@@ -504,7 +556,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 ();
@@ -677,12 +730,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 defc4259..8be39fc3 100644
--- a/dw/table.cc
+++ b/dw/table.cc
@@ -23,8 +23,6 @@
#include "../lout/msg.h"
#include "../lout/misc.hh"
-#define MAX misc::max
-
using namespace lout;
namespace dw {
@@ -62,7 +60,7 @@ Table::Table(bool limitTextWidth)
rowStyle = new misc::SimpleVector <core::style::Style*> (8);
hasColPercent = 0;
- colPercents = new misc::SimpleVector <float> (8);
+ colPercents = new misc::SimpleVector <core::style::Length> (8);
redrawX = 0;
redrawY = 0;
@@ -137,11 +135,11 @@ void Table::getExtremesImpl (core::Extremes *extremes)
}
if (core::style::isAbsLength (getStyle()->width)) {
extremes->minWidth =
- MAX (extremes->minWidth,
- core::style::absLengthVal(getStyle()->width));
+ misc::max (extremes->minWidth,
+ core::style::absLengthVal(getStyle()->width));
extremes->maxWidth =
- MAX (extremes->maxWidth,
- core::style::absLengthVal(getStyle()->width));
+ misc::max (extremes->maxWidth,
+ core::style::absLengthVal(getStyle()->width));
}
_MSG(" Table::getExtremesImpl, {%d, %d} numCols=%d\n",
@@ -297,7 +295,7 @@ void Table::addCell (Widget *widget, int colspan, int rowspan)
}
if (colspan == 0) {
- colspanEff = MAX (numCols - curCol, 1);
+ colspanEff = misc::max (numCols - curCol, 1);
rowClosed = true;
} else
colspanEff = colspan;
@@ -503,9 +501,9 @@ void Table::forceCalcCellSizes ()
* as defined by CSS2.)
*/
totalWidth =
- (int)(availWidth
- * misc::min (core::style::perLengthVal (getStyle()->width),
- 1.0));
+ misc::min (core::style::multiplyWithPerLength (availWidth,
+ getStyle()->width),
+ availWidth);
} else if (getStyle()->width == core::style::LENGTH_AUTO) {
totalWidth = availWidth;
forceTotalWidth = 0;
@@ -557,7 +555,7 @@ void Table::forceCalcCellSizes ()
children->get(n)->cell.widget->sizeRequest (&childRequisition);
childHeight = childRequisition.ascent + childRequisition.descent;
if (children->get(n)->cell.rowspan == 1) {
- rowHeight = MAX (rowHeight, childHeight);
+ rowHeight = misc::max (rowHeight, childHeight);
} else {
rowSpanCells->increase();
rowSpanCells->set(rowSpanCells->size()-1, n);
@@ -660,7 +658,7 @@ void Table::forceCalcColumnExtremes ()
for (int col = 0; col < numCols; col++) {
colExtremes->getRef(col)->minWidth = 0;
colExtremes->getRef(col)->maxWidth = 0;
- colPercents->set(col, LEN_AUTO);
+ colPercents->set(col, core::style::LENGTH_AUTO);
for (int row = 0; row < numRows; row++) {
int n = row * numCols + col;
@@ -677,8 +675,8 @@ void Table::forceCalcColumnExtremes ()
if (core::style::isAbsLength (width)) {
// Fixed lengths include table padding, border and margin.
cellMinW = cellExtremes.minWidth;
- cellMaxW = MAX (cellMinW,
- core::style::absLengthVal(width) - pbm);
+ cellMaxW = misc::max (cellMinW,
+ core::style::absLengthVal(width) - pbm);
} else {
cellMinW = cellExtremes.minWidth;
cellMaxW = cellExtremes.maxWidth;
@@ -691,22 +689,24 @@ void Table::forceCalcColumnExtremes ()
cellMinW, cellMaxW);
colExtremes->getRef(col)->minWidth =
- MAX (colExtremes->getRef(col)->minWidth, cellMinW);
+ misc::max (colExtremes->getRef(col)->minWidth, cellMinW);
colExtremes->getRef(col)->maxWidth =
- MAX (colExtremes->getRef(col)->minWidth, MAX (
- colExtremes->getRef(col)->maxWidth,
- cellMaxW));
+ misc::max (colExtremes->getRef(col)->minWidth, misc::max (
+ colExtremes->getRef(col)->maxWidth,
+ cellMaxW));
// Also fill the colPercents array in this pass
if (core::style::isPerLength (width)) {
hasColPercent = 1;
- if (colPercents->get(col) == LEN_AUTO)
- colPercents->set(col, core::style::perLengthVal(width));
+ if (colPercents->get(col) == core::style::LENGTH_AUTO)
+ colPercents->set(col, width);
} else if (core::style::isAbsLength (width)) {
// We treat LEN_ABS as a special case of LEN_AUTO.
/*
* if (colPercents->get(col) == LEN_AUTO)
* colPercents->set(col, LEN_ABS);
+ *
+ * (Hint: that's old code!)
*/
}
} else {
@@ -732,7 +732,8 @@ void Table::forceCalcColumnExtremes ()
if (core::style::isAbsLength (width)) {
// Fixed lengths include table padding, border and margin.
cellMinW = cellExtremes.minWidth;
- cellMaxW = MAX (cellMinW, core::style::absLengthVal(width) - pbm);
+ cellMaxW =
+ misc::max (cellMinW, core::style::absLengthVal(width) - pbm);
} else {
cellMinW = cellExtremes.minWidth;
cellMaxW = cellExtremes.maxWidth;
@@ -750,10 +751,10 @@ void Table::forceCalcColumnExtremes ()
continue;
// Cell size is too small; apportion {min,max} for this colspan.
- int spanMinW = MAX (MAX(cs, minSumCols),
- cellMinW - (cs-1) * getStyle()->hBorderSpacing),
- spanMaxW = MAX (MAX(cs, maxSumCols),
- cellMaxW - (cs-1) * getStyle()->hBorderSpacing);
+ int spanMinW = misc::max (misc::max (cs, minSumCols),
+ cellMinW - (cs-1) * getStyle()->hBorderSpacing),
+ spanMaxW = misc::max (misc::max (cs, maxSumCols),
+ cellMaxW - (cs-1) * getStyle()->hBorderSpacing);
if (minSumCols == 0) {
// No single cells defined for this span => pre-apportion equally
@@ -767,13 +768,13 @@ void Table::forceCalcColumnExtremes ()
}
}
- // This numbers will help if the span has percents.
+ // These values will help if the span has percents.
int spanHasColPercent = 0;
int availSpanMinW = spanMinW;
float cumSpanPercent = 0.0f;
for (int i = col; i < col + cs; ++i) {
- if (colPercents->get(i) > 0.0f) {
- cumSpanPercent += colPercents->get(i);
+ if (core::style::isPerLength (colPercents->get(i))) {
+ cumSpanPercent += core::style::perLengthVal (colPercents->get(i));
++spanHasColPercent;
} else
availSpanMinW -= colExtremes->getRef(i)->minWidth;
@@ -798,10 +799,14 @@ void Table::forceCalcColumnExtremes ()
curExtraW -= d_w;
curAppW -= d_a;
} else {
- if (colPercents->get(i) > 0.0f) {
- wMin = MAX (colExtremes->getRef(i)->minWidth,
- (int)(availSpanMinW
- * colPercents->get(i)/cumSpanPercent));
+ if (core::style::isPerLength (colPercents->get(i))) {
+ // multiplyWithPerLength would cause rounding errors,
+ // therefore the deprecated way, using perLengthVal:
+ wMin = misc::max (colExtremes->getRef(i)->minWidth,
+ (int)(availSpanMinW *
+ core::style::perLengthVal
+ (colPercents->get (i))
+ / cumSpanPercent));
colExtremes->getRef(i)->minWidth = wMin;
}
}
@@ -810,7 +815,7 @@ void Table::forceCalcColumnExtremes ()
(int)((float)(goalMaxW-cumMaxWnew)
* colExtremes->getRef(i)->maxWidth
/ (maxSumCols-cumMaxWold));
- wMax = MAX (wMin, wMax);
+ wMax = misc::max (wMin, wMax);
cumMaxWnew += wMax;
cumMaxWold += colExtremes->getRef(i)->maxWidth;
colExtremes->getRef(i)->maxWidth = wMax;
@@ -850,17 +855,18 @@ void Table::apportion2 (int totalWidth, int forceTotalWidth)
#endif
int minAutoWidth = 0, maxAutoWidth = 0, availAutoWidth = totalWidth;
for (int col = 0; col < numCols; col++) {
- if (colPercents->get(col) == LEN_ABS) { // set absolute lengths
+ if (core::style::isAbsLength (colPercents->get(col))) {
+ // set absolute lengths
setColWidth (col, colExtremes->get(col).minWidth);
}
- if (colPercents->get(col) == LEN_AUTO) {
+ if (colPercents->get(col) == core::style::LENGTH_AUTO) {
maxAutoWidth += colExtremes->get(col).maxWidth;
minAutoWidth += colExtremes->get(col).minWidth;
} else
availAutoWidth -= colWidths->get(col);
}
- if (!maxAutoWidth) // no LEN_AUTO cols!
+ if (!maxAutoWidth) // no core::style::LENGTH_AUTO cols!
return;
colWidths->setSize (colExtremes->size (), 0);
@@ -871,7 +877,7 @@ void Table::apportion2 (int totalWidth, int forceTotalWidth)
}
// General case.
- int curTargetWidth = MAX (availAutoWidth, minAutoWidth);
+ int curTargetWidth = misc::max (availAutoWidth, minAutoWidth);
int curExtraWidth = curTargetWidth - minAutoWidth;
int curMaxWidth = maxAutoWidth;
int curNewWidth = minAutoWidth;
@@ -880,7 +886,7 @@ void Table::apportion2 (int totalWidth, int forceTotalWidth)
col, colExtremes->getRef(col)->minWidth,
colExtremes->get(col).maxWidth);
- if (colPercents->get(col) != LEN_AUTO)
+ if (colPercents->get(col) != core::style::LENGTH_AUTO)
continue;
int colMinWidth = colExtremes->getRef(col)->minWidth;
@@ -937,7 +943,7 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
// It has only a table-wide percentage. Apportion non-absolute widths.
int sumMaxWidth = 0, perAvailWidth = totalWidth;
for (int col = 0; col < numCols; col++) {
- if (colPercents->get(col) == LEN_ABS)
+ if (core::style::isAbsLength (colPercents->get(col)))
perAvailWidth -= colExtremes->getRef(col)->maxWidth;
else
sumMaxWidth += colExtremes->getRef(col)->maxWidth;
@@ -948,8 +954,9 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
for (int col = 0; col < numCols; col++) {
int max_wi = colExtremes->getRef(col)->maxWidth, new_wi;
- if (colPercents->get(col) != LEN_ABS) {
- new_wi = MAX (colExtremes->getRef(col)->minWidth,
+ if (!core::style::isAbsLength (colPercents->get(col))) {
+ new_wi =
+ misc::max (colExtremes->getRef(col)->minWidth,
(int)((float)max_wi * perAvailWidth/sumMaxWidth));
setColWidth (col, new_wi);
perAvailWidth -= new_wi;
@@ -972,12 +979,13 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
int hasAutoCol = 0;
int sumMinWidth = 0, sumMaxWidth = 0, sumMinNonPer = 0, sumMaxNonPer = 0;
for (int col = 0; col < numCols; col++) {
- if (colPercents->get(col) > 0.0f) {
- cumPercent += colPercents->get(col);
+ if (core::style::isPerLength (colPercents->get(col))) {
+ cumPercent += core::style::perLengthVal (colPercents->get(col));
} else {
sumMinNonPer += colExtremes->getRef(col)->minWidth;
sumMaxNonPer += colExtremes->getRef(col)->maxWidth;
- hasAutoCol += (colPercents->get(col) == LEN_AUTO);
+ if (colPercents->get(col) == core::style::LENGTH_AUTO)
+ hasAutoCol++;
}
sumMinWidth += colExtremes->getRef(col)->minWidth;
sumMaxWidth += colExtremes->getRef(col)->maxWidth;
@@ -990,17 +998,19 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
if (!forceTotalWidth) {
if (sumMaxNonPer == 0 || cumPercent < 0.99f) {
// only percentage columns, or cumPercent < 100% => restrict width
- int totW = (int)(sumMaxNonPer/(1.0f-cumPercent));
+ int totW = (int)(sumMaxNonPer / (1.0f - cumPercent));
for (int col = 0; col < numCols; col++) {
- totW = MAX (totW, (int)(colExtremes->getRef(col)->maxWidth
- / colPercents->get(col)));
+ totW = misc::max
+ (totW,
+ (int)(colExtremes->getRef(col)->maxWidth
+ / core::style::perLengthVal (colPercents->get(col))));
}
totalWidth = misc::min (totW, totalWidth);
}
}
// make sure there's enough space
- totalWidth = MAX (totalWidth, sumMinWidth);
+ totalWidth = misc::max (totalWidth, sumMinWidth);
// extraWidth is always >= 0
int extraWidth = totalWidth - sumMinWidth;
int sumMinWidthPer = sumMinWidth - sumMinNonPer;
@@ -1019,8 +1029,9 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
for (int col = 0; col < numCols; col++) {
int colMinWidth = colExtremes->getRef(col)->minWidth;
- if (colPercents->get(col) >= 0.0f) {
- int w = (int)(workingWidth * colPercents->get(col));
+ if (core::style::isPerLength (colPercents->get(col))) {
+ int w = core::style::multiplyWithPerLength (workingWidth,
+ colPercents->get(col));
if (w < colMinWidth)
w = colMinWidth;
else if (curPerWidth - colMinWidth + w > workingWidth)
@@ -1044,7 +1055,7 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
#endif
curPerWidth -= sumMinNonPer;
int perWidth = (int)(curPerWidth/cumPercent);
- totalWidth = MAX (totalWidth, perWidth);
+ totalWidth = misc::max (totalWidth, perWidth);
totalWidth = misc::min (totalWidth, oldTotalWidth);
_MSG("APP_P, curPerWidth=%d perWidth=%d, totalWidth=%d\n",
@@ -1055,8 +1066,19 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
// We'll honor totalWidth by expanding the percentage cols.
int extraWidth = totalWidth - curPerWidth - sumMinNonPer;
for (int col = 0; col < numCols; col++) {
- if (colPercents->get(col) >= 0.0f) {
- int d = (int)(extraWidth * colPercents->get(col)/cumPercent);
+ if (core::style::isPerLength (colPercents->get(col))) {
+ // This could cause rounding errors:
+ //
+ // int d =
+ // core::dw::multiplyWithPerLength (extraWidth,
+ // colPercents->get(col))
+ // / cumPercent;
+ //
+ // Thus the "old" way:
+ int d =
+ (int)(extraWidth *
+ core::style::perLengthVal (colPercents->get(col))
+ / cumPercent);
setColWidth (col, colWidths->get(col) + d);
}
}
@@ -1073,7 +1095,7 @@ void Table::apportion_percentages2(int totalWidth, int forceTotalWidth)
#ifdef DBG
MSG("APP_P, percent={");
for (int col = 0; col < numCols; col++)
- MSG("%f ", colPercents->get(col));
+ MSG("%f ", core::dw::perLengthVal (colPercents->get(col)));
MSG("}\n");
MSG("APP_P, result ={ ");
for (int col = 0; col < numCols; col++)
diff --git a/dw/table.hh b/dw/table.hh
index b8feb835..1d14ec07 100644
--- a/dw/table.hh
+++ b/dw/table.hh
@@ -393,11 +393,9 @@ private:
/**
* hasColPercent becomes true when any cell specifies a percentage width.
- * A negative value in colPercents means LEN_AUTO or LEN_ABS.
*/
- enum { LEN_AUTO = -1, LEN_ABS = -2};
int hasColPercent;
- lout::misc::SimpleVector<float> *colPercents;
+ lout::misc::SimpleVector<core::style::Length> *colPercents;
inline bool childDefined(int n)
{
diff --git a/dw/textblock.cc b/dw/textblock.cc
index dec512d4..21aaa9dd 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -41,6 +41,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 },
@@ -188,8 +285,13 @@ Textblock::~Textblock ()
for (int i = 0; i < words->size(); i++) {
Word *word = words->getRef (i);
+
if (word->content.type == core::Content::WIDGET)
delete word->content.widget;
+
+ removeWordImgRenderer (i);
+ removeSpaceImgRenderer (i);
+
word->style->unref ();
word->spaceStyle->unref ();
}
@@ -807,8 +909,8 @@ void Textblock::calcWidgetSize (core::Widget *widget, core::Requisition *size)
size->width = core::style::absLengthVal (wstyle->width)
+ wstyle->boxDiffWidth ();
else
- size->width = (int) (core::style::perLengthVal (wstyle->width)
- * availWidth);
+ size->width =
+ core::style::multiplyWithPerLength (availWidth, wstyle->width);
if (wstyle->height == core::style::LENGTH_AUTO) {
size->ascent = requisition.ascent;
@@ -820,9 +922,10 @@ void Textblock::calcWidgetSize (core::Widget *widget, core::Requisition *size)
+ wstyle->boxDiffHeight ();
size->descent = 0;
} else {
- double len = core::style::perLengthVal (wstyle->height);
- size->ascent = (int) (len * availAscent);
- size->descent = (int) (len * availDescent);
+ size->ascent =
+ core::style::multiplyWithPerLength (wstyle->height, availAscent);
+ size->descent =
+ core::style::multiplyWithPerLength (wstyle->height, availDescent);
}
}
@@ -1353,14 +1456,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::fillWord (Word *word, int width, int ascent, int descent,
+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 (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;
@@ -1370,8 +1536,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 ();
}
@@ -1473,9 +1646,9 @@ void Textblock::calcTextSize (const char *text, size_t len,
if (core::style::isAbsLength (style->lineHeight))
height = core::style::absLengthVal(style->lineHeight);
else
- height = lout::misc::roundInt (
- core::style::perLengthVal(style->lineHeight) *
- style->font->size);
+ height =
+ core::style::multiplyWithPerLengthRounded (style->font->size,
+ style->lineHeight);
leading = height - style->font->size;
size->ascent += leading / 2;
@@ -1849,7 +2022,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 ();
}
@@ -1871,7 +2044,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:
//
@@ -1887,6 +2060,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);
// Do not override a previously set break penalty.
@@ -1904,9 +2079,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 7cf62f5c..b85937ba 100644
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -237,6 +237,44 @@ private:
static const char *hyphenDrawChar;
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 */
@@ -350,6 +388,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);
@@ -483,9 +526,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 61e58cdb..c07dc602 100644
--- a/dw/textblock_linebreaking.cc
+++ b/dw/textblock_linebreaking.cc
@@ -420,6 +420,16 @@ Textblock::Line *Textblock::addLine (int firstWord, int lastWord,
//printf (": ");
//words->getRef(line->lastWord)->badnessAndPenalty.print ();
//printf ("\n");
+
+ int xWidget = lineXOffsetWidget(line);
+ 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;
+ }
return line;
}
@@ -872,6 +882,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 ());
// Adjust anchor indexes.
@@ -883,8 +895,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.
@@ -923,7 +934,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);
@@ -1102,8 +1113,8 @@ void Textblock::initLine1Offset (int wordIndex)
/* don't use text-indent when nesting blocks */
} else {
if (core::style::isPerLength(getStyle()->textIndent)) {
- indent = misc::roundInt(this->availWidth *
- core::style::perLengthVal (getStyle()->textIndent));
+ indent = core::style::multiplyWithPerLengthRounded
+ (this->availWidth, getStyle()->textIndent);
} else {
indent = core::style::absLengthVal (getStyle()->textIndent);
}
diff --git a/dw/widget.cc b/dw/widget.cc
index 9c6fe380..415da6bc 100644
--- a/dw/widget.cc
+++ b/dw/widget.cc
@@ -32,6 +32,36 @@ 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 ()
@@ -55,6 +85,8 @@ Widget::Widget ()
deleteCallbackData = NULL;
deleteCallbackFunc = NULL;
+
+ widgetImgRenderer = NULL;
}
Widget::~Widget ()
@@ -62,6 +94,12 @@ Widget::~Widget ()
if (deleteCallbackFunc)
deleteCallbackFunc (deleteCallbackData);
+ if (widgetImgRenderer) {
+ if (style && style->backgroundImage)
+ style->backgroundImage->removeExternalImgRenderer (widgetImgRenderer);
+ delete widgetImgRenderer;
+ }
+
if (style)
style->unref ();
@@ -281,6 +319,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) {
@@ -291,6 +333,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 ();
}
@@ -340,20 +391,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);
}
/**
@@ -364,32 +426,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);
}
/*
@@ -533,6 +584,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 6942221b..34b35efa 100644
--- a/dw/widget.hh
+++ b/dw/widget.hh
@@ -74,6 +74,28 @@ protected:
BLOCK_LEVEL = 1 << 6,
};
+ /**
+ * \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.
@@ -289,6 +311,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.
*