aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Geerken <devnull@localhost>2013-12-09 14:44:42 +0100
committerSebastian Geerken <devnull@localhost>2013-12-09 14:44:42 +0100
commit01f697091153846bdffc73b3150ba37c763301cc (patch)
tree84773dff07a8498e7cc62695d89a6ecb29378a82
parentee66f4f97e38d11e68b9515b7043aa8ac6f63c74 (diff)
parent6c7572f8bd23064f96ba716e1ba8ba8a34847001 (diff)
Merge (large!).
-rw-r--r--.hgignore1
-rw-r--r--ChangeLog2
-rw-r--r--dillorc9
-rw-r--r--doc/dw-images-and-backgrounds.doc259
-rw-r--r--dw/Makefile.am2
-rw-r--r--dw/alignedtextblock.cc2
-rw-r--r--dw/core.hh1
-rw-r--r--dw/findtext.cc3
-rw-r--r--dw/fltkflatview.cc2
-rw-r--r--dw/fltkimgbuf.cc67
-rw-r--r--dw/fltkimgbuf.hh3
-rw-r--r--dw/fltkplatform.cc4
-rw-r--r--dw/fltkviewport.cc3
-rw-r--r--dw/image.cc12
-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.cc128
-rw-r--r--dw/layout.hh31
-rw-r--r--dw/listitem.cc2
-rw-r--r--dw/selection.cc3
-rw-r--r--dw/style.cc465
-rw-r--r--dw/style.hh158
-rw-r--r--dw/table.cc2
-rw-r--r--dw/tablecell.cc2
-rw-r--r--dw/textblock.cc199
-rw-r--r--dw/textblock.hh52
-rw-r--r--dw/textblock_linebreaking.cc17
-rw-r--r--dw/ui.cc2
-rw-r--r--dw/widget.cc163
-rw-r--r--dw/widget.hh24
-rw-r--r--lout/debug.hh131
-rw-r--r--src/css.hh12
-rw-r--r--src/cssparser.cc173
-rw-r--r--src/cssparser.hh3
-rw-r--r--src/dicache.c13
-rw-r--r--src/dillo.cc5
-rw-r--r--src/form.cc32
-rw-r--r--src/html.cc156
-rw-r--r--src/html_common.hh16
-rw-r--r--src/image.cc43
-rw-r--r--src/image.hh8
-rw-r--r--src/imgbuf.cc6
-rw-r--r--src/imgbuf.hh2
-rw-r--r--src/menu.cc20
-rw-r--r--src/plain.cc7
-rw-r--r--src/prefs.c1
-rw-r--r--src/prefs.h1
-rw-r--r--src/prefsparser.cc1
-rw-r--r--src/styleengine.cc149
-rw-r--r--src/styleengine.hh30
-rw-r--r--src/table.cc20
-rw-r--r--src/uicmd.cc3
-rw-r--r--src/web.cc8
-rw-r--r--test/Makefile.am9
-rw-r--r--test/dw_image_background.cc196
57 files changed, 2402 insertions, 414 deletions
diff --git a/.hgignore b/.hgignore
index 972db44a..759077b4 100644
--- a/.hgignore
+++ b/.hgignore
@@ -28,6 +28,7 @@
^test/dw-example$
^test/dw-find-test$
^test/dw-float-test$
+^test/dw-image-background$
^test/dw-images-scaled$
^test/dw-images-scaled2$
^test/dw-images-simple$
diff --git a/ChangeLog b/ChangeLog
index 0dab6ee3..98287844 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -23,6 +23,8 @@ dillo-3.0.4 [not released yet]
- Some linebreaking fixes, and optimization for non-justified text, including
new preference stretchability_factor.
- Added white_bg_replacement preference.
+ - Implemented background images (except 'background-attachment'), added
+ load_background_images preference, as well as a new entry in the tools menu.
Patches: Sebastian Geerken
+- Fix a set of bugs reported by Oulu Univ. Secure Programming Group
(HTML parsing, URL resolution, GIF processing, etc.)
diff --git a/dillorc b/dillorc
index 16207711..fc0b1019 100644
--- a/dillorc
+++ b/dillorc
@@ -14,10 +14,15 @@
# geometry=650x545+0+20
#geometry=780x580
-# Change this if you want to have text-only browsing from the start.
-# (While browsing, this can be changed from the tools/settings menu.)
+# Change this (and the following option) if you want to have text-only browsing
+# from the start. (While browsing, this can be changed from the tools/settings
+# menu.)
#load_images=YES
+# Change this if you do not want background images to be loaded initially.
+# (While browsing, this can be changed from the tools/settings menu.)
+#load_background_images=YES
+
# Change this if you want to disable loading of CSS stylesheets initially.
# (While browsing, this can be changed from the tools/settings menu.)
#load_stylesheets=YES
diff --git a/doc/dw-images-and-backgrounds.doc b/doc/dw-images-and-backgrounds.doc
index 356652a6..8f07766a 100644
--- a/doc/dw-images-and-backgrounds.doc
+++ b/doc/dw-images-and-backgrounds.doc
@@ -1,10 +1,11 @@
/** \page dw-images-and-backgrounds Images and Backgrounds in Dw
-<h2>General</h2>
+Image Buffers
+=============
-Representation of the image data is delegated to dw::core::Imgbuf, see
-there for details. Drawing is delegated to dw::core::View
-(dw::core::View::drawImgbuf).
+Representation of the image data is done by dw::core::Imgbuf, see
+there for details. Drawing is done by dw::core::View
+(dw::core::View::drawImage).
Since dw::core::Imgbuf provides memory management based on reference
counting, there may be an 1-to-n relation from image renderers (image
@@ -15,61 +16,73 @@ dw::core::Imgbuf::copyRow) notify all renderers connected to the
buffer.
-<h2>Images</h2>
+Image Renderer
+==============
+
+Generally, there are no restrictions on how to manage
+dw::core::Imgbuf; but to handle image data from web resources, the
+interface dw::core::ImgRenderer should be implemented. It is again
+wrapped by DilloImage (to make access from the C part possible, since
+dw::core::ImgRenderer is written in C++), which is referenced by
+DilloWeb. There are two positions where retrieving image data is
+initiated:
+
+- Html_load_image: for embedded images (implemented by dw::Image,
+ which implements dw::core::ImgRenderer);
+- StyleEngine::apply (search for "case
+ CSS_PROPERTY_BACKGROUND_IMAGE"): for backgrond images; there are
+ some implementations of dw::core::ImgRenderer within the context of
+ dw::core::style::StyleImage.
+
+Both are described in detail below. Notice that the code is quite
+similar; only the implementation of dw::core::ImgRenderer differs.
+
+At this time, dw::core::ImgRenderer has got two methods (see more
+documentation there):
+
+- dw::core::ImgRenderer::setBuffer,
+- dw::core::ImgRenderer::drawRow,
+- dw::core::ImgRenderer::finish, and
+- dw::core::ImgRenderer::fatal.
+
+
+Images
+======
This is the simplest renderer, displaying an image. For each row to be
drawn,
-<ol>
-<li> first dw::core::Imgbuf::copyRow, and then
-<li> for each dw::Image, dw::Image::drawRow must be called, with the same
- argument (no scaling is necessary).
-</ol>
+- first dw::core::Imgbuf::copyRow, and then
+- for each dw::Image, dw::Image::drawRow must be called, with the same
+ argument (no scaling is necessary).
dw::Image automatically scales the dw::core::Imgbuf, the root buffer
should be passed to dw::Image::setBuffer.
\see dw::Image for more details.
-<h2>Future Extensions</h2>
-(This is not implemented yet.) Rendering itself (image widgets and
-background) will be abstracted, by a new interface
-dw::core::ImageRenderer. In the current code for image decoding, this
-interface will replace references to dw::Image, which implements
-dw::core::ImageRenderer, in most cases.
+Background Images
+=================
-<h2>Backgrounds</h2>
+Since background images are style resources, they are associated with
+dw::core::style::Style, as dw::core::style::StyleImage, which is
+handled in a similar way (reference counting etc.) as
+dw::core::style::Color and dw::core::style::Font, although it is
+concrete and not platform-dependant.
-(This is based on future extensions described above.) Since background
-are style resources, they are associated with
-dw::core::style::Style. For backgrounds, another level is needed,
-because of the 1-to-n relation from dw::core::style::Style to
-dw::core::Widget:
+The actual renderer (passed to Web) is an instance of
+dw::core::ImgRendererDist (distributes all calls to a set of other
+instances of dw::core::ImgRenderer), which contains two kinds of
+renderers:
-\dot
-digraph G {
- node [shape=record, fontname=Helvetica, fontsize=10];
- edge [arrowhead="open", dir="both", arrowtail="none",
- labelfontname=Helvetica, labelfontsize=10, color="#404040",
- labelfontcolor="#000080"];
- fontname=Helvetica; fontsize=10;
-
- "background renderer (as a part of style)" -> "image buffer" [headlabel="*",
- taillabel="1"];
- "widget (or a part of it)" -> "background renderer (as a part of style)"
- [headlabel="*", taillabel="1"];
-}
-\enddot
-
-Unlike dw::Image, dw::core::style::BgRenderer is not associated with a
-certain rectangle on the canvas. Instead, widgets, or parts of widgets
-take this role. This is generally represented by an implementation of
-the interface dw::core::style::BgAllocation, which is implemented by
-dw::core::Widget, but also by all parts of widget implementation,
-which may have an own background image.
+- one instance of dw::core::style::StyleImage::StyleImgRenderer, which
+ does everything needed for dw::core::style::StyleImage, and
+- other renderers, used externally (widgets etc.), which are added by
+ dw::core::style::StyleImage::putExternalImgRenderer (and removed by
+ dw::core::style::StyleImage::removeExternalImgRenderer).
-The following diagram gives a total overview:
+This diagram gives an comprehensive overview:
\dot
digraph G {
@@ -79,70 +92,144 @@ digraph G {
labelfontcolor="#000080"];
fontname=Helvetica; fontsize=10;
- "DICache Entry";
-
- subgraph cluster_dw_images {
+ subgraph cluster_dw_style {
style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
- label="Dw Images";
- ImageRenderer [URL="\ref dw::core::ImageRenderer", color="#ff8080"];
- Imgbuf [URL="\ref dw::core::Imgbuf", color="#ff8080"];
+ Style [URL="\ref dw::core::style::Style"];
+ StyleImage [URL="\ref dw::core::style::StyleImage"];
+ Imgbuf [URL="\ref dw::core::Imgbuf", color="#a0a0a0"];
+ StyleImgRenderer
+ [URL="\ref dw::core::style::StyleImage::StyleImgRenderer"];
+ ImgRenderer [URL="\ref dw::core::ImgRenderer", color="#ff8080"];
+ ImgRendererDist [URL="\ref dw::core::ImgRendererDist"];
+ ExternalImgRenderer
+ [URL="\ref dw::core::style::StyleImage::ExternalImgRenderer",
+ color="#a0a0a0"];
+ ExternalWidgetImgRenderer
+ [URL="\ref dw::core::style::StyleImage::ExternalWidgetImgRenderer",
+ color="#a0a0a0"];
}
- subgraph cluster_widgets {
+ subgraph cluster_dw_layout {
style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
- label="Widgets";
- Widget [URL="\ref dw::core::Widget", color="#a0a0a0"];
- Textblock [URL="\ref dw::Textblock"];
- "Textblock::Word" [URL="\ref dw::Textblock::Word"];
- Table [URL="\ref dw::Table"];
- "Table::Row" [URL="\ref dw::Table::Row"];
- Image [URL="\ref dw::Image"];
+ Layout [URL="\ref dw::core::Layout"];
+ LayoutImgRenderer [URL="\ref dw::core::Layout::LayoutImgRenderer"];
}
- subgraph cluster_style {
+ subgraph cluster_dw_widget {
style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
- label="dw::core::style";
- Style [URL="\ref dw::core::style::Style"];
- BgRenderer [URL="\ref dw::core::style::BgRenderer"];
- BgAllocation [URL="\ref dw::core::style::BgAllocation", color="#ff8080"];
+ Widget [URL="\ref dw::core::Widget", color="#a0a0a0"];
+ WidgetImgRenderer [URL="\ref dw::core::Widget::WidgetImgRenderer"];
}
- "DICache Entry" -> ImageRenderer [headlabel="*", taillabel="1"];
- "DICache Entry" -> Imgbuf [headlabel="1", taillabel="1"];
-
- BgRenderer -> Imgbuf [headlabel="1", taillabel="*"];
- BgRenderer -> BgAllocation [headlabel="*", taillabel="1"];
- ImageRenderer -> BgRenderer [arrowhead="none", arrowtail="empty", dir="both",
- style="dashed"];
- ImageRenderer -> Image [arrowhead="none", arrowtail="empty", dir="both",
- style="dashed"];
-
- Style -> BgRenderer [headlabel="0..1", taillabel="1"];
+ subgraph cluster_dw_textblock {
+ style="dashed"; color="#000080"; fontname=Helvetica; fontsize=10;
- Widget -> Textblock [arrowhead="none", arrowtail="empty", dir="both"];
- Textblock -> "Textblock::Word" [headlabel="*", taillabel="1"];
- Widget -> Table [arrowhead="none", arrowtail="empty", dir="both"];
- Table -> "Table::Row" [headlabel="*", taillabel="1"];
- Widget -> Image [arrowhead="none", arrowtail="empty", dir="both"];
+ Textblock [URL="\ref dw::Textblock"];
+ Word [URL="\ref dw::Textblock::Word"];
+ WordImgRenderer [URL="\ref dw::Textblock::WordImgRenderer"];
+ SpaceImgRenderer [URL="\ref dw::Textblock::SpaceImgRenderer"];
+ }
- BgAllocation -> Widget [arrowhead="none", arrowtail="empty", dir="both",
- style="dashed"];
- BgAllocation -> "Textblock::Word" [arrowhead="none", arrowtail="empty",
+ Style -> StyleImage [headlabel="*", taillabel="1"];
+ StyleImage -> Imgbuf [headlabel="*", taillabel="1"];
+ StyleImage -> StyleImgRenderer [headlabel="1", taillabel="1"];
+ StyleImage -> ImgRendererDist [headlabel="1", taillabel="1"];
+ ImgRendererDist -> StyleImgRenderer [headlabel="1", taillabel="1"];
+ ImgRendererDist -> ImgRenderer [headlabel="1", taillabel="*"];
+
+ ImgRenderer -> ImgRendererDist [arrowhead="none", arrowtail="empty",
+ dir="both", style="dashed"];
+ ImgRenderer -> StyleImgRenderer [arrowhead="none", arrowtail="empty",
+ dir="both", style="dashed"];
+ ImgRenderer -> ExternalImgRenderer [arrowhead="none", arrowtail="empty",
dir="both", style="dashed"];
- BgAllocation -> "Table::Row" [arrowhead="none", arrowtail="empty",
- dir="both", style="dashed"];
+ ExternalImgRenderer -> ExternalWidgetImgRenderer [arrowhead="none",
+ arrowtail="empty", dir="both", style="dashed"];
+
+ Layout -> LayoutImgRenderer [headlabel="1", taillabel="0..1"];
+ ExternalImgRenderer -> LayoutImgRenderer [arrowhead="none",
+ arrowtail="empty", dir="both", style="dashed"];
+
+ Widget -> WidgetImgRenderer [headlabel="1", taillabel="0..1"];
+ ExternalWidgetImgRenderer -> WidgetImgRenderer [arrowhead="none",
+ arrowtail="empty", dir="both", style="dashed"];
+
+ Textblock -> Word [headlabel="1", taillabel="*"];
+ Word -> WordImgRenderer [headlabel="1", taillabel="0..1"];
+ Word -> SpaceImgRenderer [headlabel="1", taillabel="0..1"];
+ ExternalWidgetImgRenderer -> WordImgRenderer [arrowhead="none",
+ arrowtail="empty", dir="both", style="dashed"];
+ WordImgRenderer -> SpaceImgRenderer [arrowhead="none", arrowtail="empty",
+ dir="both", style="dashed"];
}
\enddot
<center>[\ref uml-legend "legend"]</center>
-<h2>Integration into dillo</h2>
+Memory management
+-----------------
+
+dw::core::style::StyleImage extends lout::signal::ObservedObject, so
+that deleting this instance can be connected to code dealing with
+cache clients etc. See StyleImageDeletionReceiver and how it is
+attached in StyleEngine::apply ("case CSS_PROPERTY_BACKGROUND_IMAGE").
+
+
+Bugs and Things Needing Improvement
+===================================
+
+(Mostly related to image backgrounds, when not otherwise mentioned.)
+
+High Priority
+-------------
+
+**Configurability, security/privacy aspects, etc.,** which are
+currently available for image widgets, should be adopted. Perhaps some
+more configuration options specially for background images.
+
+
+Medium Priority
+---------------
+
+**Background-attachment** is not yet implemented, and will be postponed.
+
+**Calls to dw::core::ImgRenderer::fatal** are incomplete. As an
+example, it is not called, when connecting to a server fails. (And so,
+as far as I see, no cache client is started.)
+
+
+Low Priority
+------------
+
+**Alpha support:** (not related to image backgrounds) currently alpha
+support (and also colormap management) is done in dicache, while
+dw::Image is only created with type RGB. This leads to several problems:
+
+- One dicache entry (representing an image related to the same URL),
+ which has only one background color, may refer to different images
+ with different background colors.
+- The dicache only handles background colors, not background images.
+
+The solution is basicly simple: keep alpha support out of dicache;
+instead implement RGBA in dw::Image. As it seems, the main problem is
+alpha support in FLTK/X11.
+
+
+Solved (Must Be Documented)
+---------------------------
-\todo Add some references.
+*Drawing background images row by row may become slow. As an
+alternative, dw::core::ImgRenderer::finish could be used. However,
+drawing row by row could become an option.* There is now
+dw::core::style::drawBackgroundLineByLine, which can be changed in the
+code, and is set to *false*. The old code still exists, so changing
+this to *true* activates again drawing line by line.
+(For image widgets, this could also become an option: in contexts,
+when image data is retrieved in a very fast way.)
*/
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);
}
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/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);
diff --git a/dw/ui.cc b/dw/ui.cc
index 374f360b..17cf2288 100644
--- a/dw/ui.cc
+++ b/dw/ui.cc
@@ -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.
*
diff --git a/lout/debug.hh b/lout/debug.hh
index a2c08393..bbbe401b 100644
--- a/lout/debug.hh
+++ b/lout/debug.hh
@@ -30,7 +30,7 @@
/*
- * Following is experimental, and will be explained soon.
+ * See <http://www.dillo.org/~sgeerken/rtfl/>.
*/
#ifdef DBG_RTFL
@@ -38,111 +38,138 @@
#include <unistd.h>
#include <stdio.h>
-#define DBG_MSG(obj, aspect, prio, msg) \
+#define RTFL_PREFIX_FMT "[rtfl]%s:%d:%d:"
+#define RTFL_PREFIX_ARGS __FILE__, __LINE__, getpid()
+
+#define DBG_OBJ_MSG(aspect, prio, msg) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:%s\n", \
+ RTFL_PREFIX_ARGS, this, aspect, prio, msg); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_MSGF(aspect, prio, fmt, ...) \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-msg:%p:%s:%d:" fmt "\n", \
+ RTFL_PREFIX_ARGS, this, aspect, prio, __VA_ARGS__); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_MSG_START() \
+ D_STMT_START { \
+ printf (RTFL_PREFIX_FMT "obj-msg-start:%p\n", \
+ RTFL_PREFIX_ARGS, this); \
+ fflush (stdout); \
+ } D_STMT_END
+
+#define DBG_OBJ_MSG_END() \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:msg:%p:%s:%d:%s\n", \
- __FILE__, __LINE__, getpid(), obj, aspect, prio, msg); \
+ printf (RTFL_PREFIX_FMT "obj-msg-end:%p\n", \
+ RTFL_PREFIX_ARGS, this); \
fflush (stdout); \
} D_STMT_END
-#define DBG_MSGF(obj, aspect, prio, fmt, ...) \
+#define DBG_OBJ_CREATE(klass) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:msg:%p:%s:%d:" fmt "\n", \
- __FILE__, __LINE__, getpid(), obj, aspect, prio, __VA_ARGS__); \
+ printf (RTFL_PREFIX_FMT "obj-create:%p:%s\n", \
+ RTFL_PREFIX_ARGS, this, klass); \
fflush (stdout); \
} D_STMT_END
-#define DBG_MSG_START(obj) \
+#define DBG_OBJ_BASECLASS(klass) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:msg-start:%p\n", \
- __FILE__, __LINE__, getpid(), obj); \
+ printf (RTFL_PREFIX_FMT "obj-ident:%p:%p\n", \
+ RTFL_PREFIX_ARGS, this, (klass*)this); \
fflush (stdout); \
} D_STMT_END
-#define DBG_MSG_END(obj) \
+#define DBG_OBJ_ASSOC(parent, child) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:msg-end:%p\n", \
- __FILE__, __LINE__, getpid(), obj); \
+ printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
+ RTFL_PREFIX_ARGS, parent, child); \
fflush (stdout); \
} D_STMT_END
-#define DBG_OBJ_CREATE(obj, klass) \
+#define DBG_OBJ_ASSOC_PARENT(parent) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:obj-create:%p:%s\n", \
- __FILE__, __LINE__, getpid(), obj, klass); \
+ printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
+ RTFL_PREFIX_ARGS, parent, this); \
fflush (stdout); \
} D_STMT_END
-#define DBG_OBJ_ASSOC(child, parent) \
+#define DBG_OBJ_ASSOC_CHILD(child) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:obj-assoc:%p:%p\n", \
- __FILE__, __LINE__, getpid(), child, parent); \
+ printf (RTFL_PREFIX_FMT "obj-assoc:%p:%p\n", \
+ RTFL_PREFIX_ARGS, this, child); \
fflush (stdout); \
} D_STMT_END
-#define DBG_OBJ_SET_NUM(obj, var, val) \
+#define DBG_OBJ_SET_NUM(var, val) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:obj-set:%p:%s:%d\n", \
- __FILE__, __LINE__, getpid(), obj, var, val); \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%d\n", \
+ RTFL_PREFIX_ARGS, this, var, val); \
fflush (stdout); \
} D_STMT_END
-#define DBG_OBJ_SET_STR(obj, var, val) \
+#define DBG_OBJ_SET_STR(var, val) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:obj-set:%p:%s:%s\n", \
- __FILE__, __LINE__, getpid(), obj, var, val); \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%s\n", \
+ RTFL_PREFIX_ARGS, this, var, val); \
fflush (stdout); \
} D_STMT_END
-#define DBG_OBJ_SET_PTR(obj, var, val) \
+#define DBG_OBJ_SET_PTR(var, val) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:obj-set:%p:%s:%p\n", \
- __FILE__, __LINE__, getpid(), obj, var, val); \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:%s:%p\n", \
+ RTFL_PREFIX_ARGS, this, var, val); \
fflush (stdout); \
} D_STMT_END
-#define DBG_OBJ_ARRSET_NUM(obj, var, ind, val) \
+#define DBG_OBJ_ARRSET_NUM(var, ind, val) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:obj-set:%p:" var ":%d\n", \
- __FILE__, __LINE__, getpid(), obj, ind, val); \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:" var ".%d:%d\n", \
+ RTFL_PREFIX_ARGS, this, ind, val); \
fflush (stdout); \
} D_STMT_END
-#define DBG_OBJ_ARRSET_STR(obj, var, ind, val) \
+#define DBG_OBJ_ARRSET_STR(var, ind, val) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:obj-set:%p:" var ":%s\n", \
- __FILE__, __LINE__, getpid(), obj, ind, val); \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:" var ".%d:%s\n", \
+ RTFL_PREFIX_ARGS, this, ind, val); \
fflush (stdout); \
} D_STMT_END
-#define DBG_OBJ_ARRSET_PTR(obj, var, ind, val) \
+#define DBG_OBJ_ARRSET_PTR(var, ind, val) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:obj-set:%p:" var ":%p\n", \
- __FILE__, __LINE__, getpid(), obj, ind, val); \
+ printf (RTFL_PREFIX_FMT "obj-set:%p:" var ".%d:%p\n", \
+ RTFL_PREFIX_ARGS, this, ind, val); \
fflush (stdout); \
} D_STMT_END
-#define DBG_OBJ_COLOR(klass, color) \
+#define DBG_OBJ_COLOR(color, klass) \
D_STMT_START { \
- printf ("[rtfl]%s:%d:%d:obj-color:%s:%s\n", \
- __FILE__, __LINE__, getpid(), klass, color); \
+ printf (RTFL_PREFIX_FMT "obj-color:%s:%s\n", \
+ RTFL_PREFIX_ARGS, color, klass); \
fflush (stdout); \
} D_STMT_END
#else /* DBG_RTFL */
-#define DBG_MSG(obj, aspect, prio, msg)
-#define DBG_MSGF(obj, aspect, prio, fmt, ...)
-#define DBG_MSG_START(obj)
-#define DBG_MSG_END(obj)
-#define DBG_OBJ_CREATE(obj, klass)
-#define DBG_OBJ_ASSOC(child, parent)
-#define DBG_OBJ_SET_NUM(obj, var, val)
-#define DBG_OBJ_SET_STR(obj, var, val)
-#define DBG_OBJ_SET_PTR(obj, var, val)
-#define DBG_OBJ_ARRSET_NUM(obj, var, ind, val)
-#define DBG_OBJ_ARRSET_STR(obj, var, ind, val)
-#define DBG_OBJ_ARRSET_PTR(obj, var, ind, val)
+#define DBG_OBJ_MSG(aspect, prio, msg)
+#define DBG_OBJ_MSGF(aspect, prio, fmt, ...)
+#define DBG_OBJ_MSG_START(obj)
+#define DBG_OBJ_MSG_END(obj)
+#define DBG_OBJ_CREATE(klass)
+#define DBG_OBJ_BASECLASS(klass)
+#define DBG_OBJ_ASSOC_PARENT(parent)
+#define DBG_OBJ_ASSOC_CHILD(child)
+#define DBG_OBJ_ASSOC(parent, child)
+#define DBG_OBJ_SET_NUM(var, val)
+#define DBG_OBJ_SET_STR(var, val)
+#define DBG_OBJ_SET_PTR(var, val)
+#define DBG_OBJ_ARRSET_NUM(var, ind, val)
+#define DBG_OBJ_ARRSET_STR(var, ind, val)
+#define DBG_OBJ_ARRSET_PTR(var, ind, val)
#define DBG_OBJ_COLOR(klass, color)
#endif /* DBG_RTFL */
diff --git a/src/css.hh b/src/css.hh
index 6b142827..a7143c27 100644
--- a/src/css.hh
+++ b/src/css.hh
@@ -37,6 +37,8 @@ typedef enum {
'margin-*-width'). */
CSS_TYPE_SIGNED_LENGTH, /* As CSS_TYPE_LENGTH but may be negative. */
CSS_TYPE_LENGTH_PERCENTAGE_NUMBER, /* <length> or <percentage>, or <number> */
+ CSS_TYPE_AUTO, /* Represented as CssLength of type
+ CSS_LENGTH_TYPE_AUTO */
CSS_TYPE_COLOR, /* Represented as integer. */
CSS_TYPE_FONT_WEIGHT, /* this very special and only used by
'font-weight' */
@@ -45,6 +47,8 @@ typedef enum {
opposed to CSS_TYPE_ENUM and
CSS_TYPE_MULTI_ENUM). Used for
'font-family'. */
+ CSS_TYPE_URI, /* <uri> */
+ CSS_TYPE_BACKGROUND_POSITION,
CSS_TYPE_UNUSED /* Not yet used. Will itself get unused some
day. */
} CssValueType;
@@ -229,9 +233,15 @@ typedef enum {
CSS_PROPERTY_LAST
} CssPropertyName;
+typedef struct {
+ int32_t posX;
+ int32_t posY;
+} CssBackgroundPosition;
+
typedef union {
int32_t intVal;
char *strVal;
+ CssBackgroundPosition *posVal;
} CssPropertyValue;
typedef enum {
@@ -285,6 +295,8 @@ class CssProperty {
case CSS_TYPE_SYMBOL:
dFree (value.strVal);
break;
+ case CSS_TYPE_BACKGROUND_POSITION:
+ dFree (value.posVal);
default:
break;
}
diff --git a/src/cssparser.cc b/src/cssparser.cc
index 67d8ff54..4ff8f4f7 100644
--- a/src/cssparser.cc
+++ b/src/cssparser.cc
@@ -47,6 +47,14 @@ typedef struct {
const char *const *enum_symbols;
} CssPropertyInfo;
+static const char *const Css_background_attachment_enum_vals[] = {
+ "scroll", "fixed", NULL
+};
+
+static const char *const Css_background_repeat_enum_vals[] = {
+ "repeat", "repeat-x", "repeat-y", "no-repeat", NULL
+};
+
static const char *const Css_border_collapse_enum_vals[] = {
"separate", "collapse", NULL
};
@@ -151,11 +159,14 @@ static const char *const Css_word_spacing_enum_vals[] = {
};
const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
- {"background-attachment", {CSS_TYPE_UNUSED}, NULL},
+ {"background-attachment", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED},
+ Css_background_attachment_enum_vals},
{"background-color", {CSS_TYPE_COLOR, CSS_TYPE_UNUSED}, NULL},
- {"background-image", {CSS_TYPE_UNUSED}, NULL},
- {"background-position", {CSS_TYPE_UNUSED}, NULL},
- {"background-repeat", {CSS_TYPE_UNUSED}, NULL},
+ {"background-image", {CSS_TYPE_URI, CSS_TYPE_UNUSED}, NULL},
+ {"background-position", {CSS_TYPE_BACKGROUND_POSITION, CSS_TYPE_UNUSED},
+ NULL},
+ {"background-repeat", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED},
+ Css_background_repeat_enum_vals},
{"border-bottom-color", {CSS_TYPE_ENUM, CSS_TYPE_COLOR, CSS_TYPE_UNUSED},
Css_border_color_enum_vals},
{"border-bottom-style", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED},
@@ -206,8 +217,8 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
Css_font_variant_enum_vals},
{"font-weight", {CSS_TYPE_ENUM, CSS_TYPE_FONT_WEIGHT, CSS_TYPE_UNUSED},
Css_font_weight_enum_vals},
- {"height", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL},
- {"left", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL},
+ {"height", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL},
+ {"left", {CSS_TYPE_UNUSED}, NULL},
{"letter-spacing", {CSS_TYPE_ENUM, CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED},
Css_letter_spacing_enum_vals},
{"line-height",
@@ -218,10 +229,14 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
Css_list_style_position_enum_vals},
{"list-style-type", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED},
Css_list_style_type_enum_vals},
- {"margin-bottom", {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
- {"margin-left", {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
- {"margin-right", {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
- {"margin-top", {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED}, NULL},
+ {"margin-bottom",
+ {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL},
+ {"margin-left",
+ {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL},
+ {"margin-right",
+ {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL},
+ {"margin-top",
+ {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL},
{"marker-offset", {CSS_TYPE_UNUSED}, NULL},
{"marks", {CSS_TYPE_UNUSED}, NULL},
{"max-height", {CSS_TYPE_UNUSED}, NULL},
@@ -251,7 +266,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = {
{"vertical-align",{CSS_TYPE_ENUM, CSS_TYPE_UNUSED},Css_vertical_align_vals},
{"visibility", {CSS_TYPE_UNUSED}, NULL},
{"white-space", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_white_space_vals},
- {"width", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL},
+ {"width", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL},
{"word-spacing", {CSS_TYPE_ENUM, CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_UNUSED},
Css_word_spacing_enum_vals},
{"z-index", {CSS_TYPE_UNUSED}, NULL},
@@ -706,6 +721,15 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type)
}
break;
+ case CSS_TYPE_BACKGROUND_POSITION:
+ if (ttype == CSS_TK_SYMBOL &&
+ (dStrAsciiCasecmp(tval, "center") == 0 ||
+ dStrAsciiCasecmp(tval, "left") == 0 ||
+ dStrAsciiCasecmp(tval, "right") == 0 ||
+ dStrAsciiCasecmp(tval, "top") == 0 ||
+ dStrAsciiCasecmp(tval, "bottom") == 0))
+ return true;
+ // Fall Through (lenght and percentage)
case CSS_TYPE_LENGTH_PERCENTAGE:
case CSS_TYPE_LENGTH_PERCENTAGE_NUMBER:
case CSS_TYPE_LENGTH:
@@ -713,9 +737,12 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type)
return false;
// Fall Through
case CSS_TYPE_SIGNED_LENGTH:
- if (ttype == CSS_TK_DECINT ||
- ttype == CSS_TK_FLOAT ||
- (ttype == CSS_TK_SYMBOL && dStrAsciiCasecmp(tval, "auto") == 0))
+ if (ttype == CSS_TK_DECINT || ttype == CSS_TK_FLOAT)
+ return true;
+ break;
+
+ case CSS_TYPE_AUTO:
+ if (ttype == CSS_TK_SYMBOL && dStrAsciiCasecmp(tval, "auto") == 0)
return true;
break;
@@ -746,6 +773,12 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type)
}
break;
+ case CSS_TYPE_URI:
+ if (ttype == CSS_TK_SYMBOL &&
+ dStrAsciiCasecmp(tval, "url") == 0)
+ return true;
+ break;
+
case CSS_TYPE_UNUSED:
case CSS_TYPE_INTEGER:
/* Not used for parser values. */
@@ -939,13 +972,16 @@ bool CssParser::parseValue(CssPropertyName prop,
ret = true;
val->intVal = CSS_CREATE_LENGTH(fval, lentype);
- } else if (ttype == CSS_TK_SYMBOL && !dStrAsciiCasecmp(tval, "auto")) {
- ret = true;
- val->intVal = CSS_LENGTH_TYPE_AUTO;
- nextToken();
}
break;
+ case CSS_TYPE_AUTO:
+ assert (ttype == CSS_TK_SYMBOL && !dStrAsciiCasecmp(tval, "auto"));
+ ret = true;
+ val->intVal = CSS_LENGTH_TYPE_AUTO;
+ nextToken();
+ break;
+
case CSS_TYPE_COLOR:
if (ttype == CSS_TK_COLOR) {
val->intVal = a_Color_parse(tval, -1, &err);
@@ -1016,6 +1052,107 @@ bool CssParser::parseValue(CssPropertyName prop,
}
break;
+ case CSS_TYPE_URI:
+ if (ttype == CSS_TK_SYMBOL &&
+ dStrAsciiCasecmp(tval, "url") == 0) {
+ val->strVal = parseUrl();
+ nextToken();
+ if (val->strVal)
+ ret = true;
+ }
+ break;
+
+ case CSS_TYPE_BACKGROUND_POSITION:
+ // 'background-position' consists of one or two values: vertical and
+ // horizontal position; in most cases in this order. However, as long it
+ // is unambigous, the order can be switched: "10px left" and "left 10px"
+ // are both possible and have the same effect. For this reason, all
+ // possibilities are tested in parallel.
+
+ bool h[2], v[2];
+ int pos[2];
+ h[0] = v[0] = h[1] = v[1] = false;
+
+ // First: collect values in pos[0] and pos[1], and determine whether
+ // they can be used for a horizontal (h[i]) or vertical (v[i]) position
+ // (or both). When neither h[i] or v[i] is set, pos[i] is undefined.
+ for (i = 0; i < 2; i++) {
+ CssValueType typeTmp;
+ // tokenMatchesProperty will, for CSS_PROPERTY_BACKGROUND_POSITION,
+ // work on both parts, since they are exchangable.
+ if (tokenMatchesProperty (CSS_PROPERTY_BACKGROUND_POSITION,
+ &typeTmp)) {
+ h[i] = ttype != CSS_TK_SYMBOL ||
+ (dStrAsciiCasecmp(tval, "top") != 0 &&
+ dStrAsciiCasecmp(tval, "bottom") != 0);
+ v[i] = ttype != CSS_TK_SYMBOL ||
+ (dStrAsciiCasecmp(tval, "left") != 0 &&
+ dStrAsciiCasecmp(tval, "right") != 0);
+ } else
+ // No match.
+ h[i] = v[i] = false;
+
+ if (h[i] || v[i]) {
+ // Calculate values.
+ if (ttype == CSS_TK_SYMBOL) {
+ if (dStrAsciiCasecmp(tval, "top") == 0 ||
+ dStrAsciiCasecmp(tval, "left") == 0) {
+ pos[i] = CSS_CREATE_LENGTH (0.0, CSS_LENGTH_TYPE_PERCENTAGE);
+ nextToken();
+ } else if (dStrAsciiCasecmp(tval, "center") == 0) {
+ pos[i] = CSS_CREATE_LENGTH (0.5, CSS_LENGTH_TYPE_PERCENTAGE);
+ nextToken();
+ } else if (dStrAsciiCasecmp(tval, "bottom") == 0 ||
+ dStrAsciiCasecmp(tval, "right") == 0) {
+ pos[i] = CSS_CREATE_LENGTH (1.0, CSS_LENGTH_TYPE_PERCENTAGE);
+ nextToken();
+ } else
+ // tokenMatchesProperty should have returned "false" already.
+ lout::misc::assertNotReached ();
+ } else {
+ // We can assume <length> or <percentage> here ...
+ CssPropertyValue valTmp;
+ if (parseValue(prop, CSS_TYPE_LENGTH_PERCENTAGE, &valTmp)) {
+ pos[i] = valTmp.intVal;
+ ret = true;
+ } else
+ // ... but something may still fail.
+ h[i] = v[i] = false;
+ }
+ }
+
+ // If the first value cannot be read, do not read the second.
+ if (!h[i] && !v[i])
+ break;
+ }
+
+ // Second: Create the final value. Order will be determined here.
+ if (v[0] || h[0]) {
+ // If second value is not set, it is set to "center", i. e. 50%, (see
+ // CSS specification), which is suitable for both dimensions.
+ if (!h[1] && !v[1]) {
+ pos[1] = CSS_CREATE_LENGTH (0.5, CSS_LENGTH_TYPE_PERCENTAGE);
+ h[1] = v[1] = true;
+ }
+
+ // Only valid, when a combination h/v or v/h is possible.
+ if ((h[0] && v[1]) || (v[0] && h[1])) {
+ ret = true;
+ val->posVal = dNew(CssBackgroundPosition, 1);
+
+ // Prefer combination h/v:
+ if (h[0] && v[1]) {
+ val->posVal->posX = pos[0];
+ val->posVal->posY = pos[1];
+ } else {
+ // This should be v/h:
+ val->posVal->posX = pos[1];
+ val->posVal->posY = pos[0];
+ }
+ }
+ }
+ break;
+
case CSS_TYPE_UNUSED:
/* nothing */
break;
diff --git a/src/cssparser.hh b/src/cssparser.hh
index 8609877b..30d02eee 100644
--- a/src/cssparser.hh
+++ b/src/cssparser.hh
@@ -2,7 +2,8 @@
#define __CSSPARSER_HH__
#include "css.hh"
-#include "html_common.hh"
+
+class DilloHtml;
class CssParser {
private:
diff --git a/src/dicache.c b/src/dicache.c
index 55232846..db3b86b2 100644
--- a/src/dicache.c
+++ b/src/dicache.c
@@ -276,7 +276,8 @@ void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image,
/* BUG: there's just one image-type now */
#define I_RGB 0
- DicEntry->v_imgbuf = a_Imgbuf_new(Image->dw, I_RGB, width, height, gamma);
+ DicEntry->v_imgbuf =
+ a_Imgbuf_new(Image->layout, I_RGB, width, height, gamma);
DicEntry->TotalSize = width * height * 3;
DicEntry->width = width;
@@ -402,7 +403,8 @@ static void *Dicache_image(int ImgType, const char *MimeType, void *Ptr,
dReturn_val_if_fail(MimeType && Ptr, NULL);
if (!web->Image) {
- web->Image = a_Image_new(NULL, web->bgColor);
+ web->Image =
+ a_Image_new_with_dw(web->bw->render_layout, NULL, web->bgColor);
a_Image_ref(web->Image);
}
@@ -429,7 +431,7 @@ static void *Dicache_image(int ImgType, const char *MimeType, void *Ptr,
*Data = DicEntry->DecoderData;
*Call = (CA_Callback_t) a_Dicache_callback;
- return (web->Image->dw);
+ return (a_Image_get_dw (web->Image));
}
/*
@@ -516,9 +518,12 @@ void a_Dicache_callback(int Op, CacheClient_t *Client)
Image->ScanNumber = DicEntry->ScanNumber;
}
}
- } else if (Op == CA_Close || Op == CA_Abort) {
+ } else if (Op == CA_Close) {
a_Image_close(Image);
a_Bw_close_client(Web->bw, Client->Key);
+ } else if (Op == CA_Abort) {
+ a_Image_abort(Image);
+ a_Bw_close_client(Web->bw, Client->Key);
}
}
diff --git a/src/dillo.cc b/src/dillo.cc
index e519d4df..2b9f1645 100644
--- a/src/dillo.cc
+++ b/src/dillo.cc
@@ -53,6 +53,7 @@
#include "domain.h"
#include "auth.h"
+#include "lout/debug.hh"
#include "dw/fltkcore.hh"
#include "dw/textblock.hh"
@@ -375,6 +376,10 @@ static DilloUrl *makeStartUrl(char *str, bool local)
*/
int main(int argc, char **argv)
{
+ DBG_OBJ_COLOR("#c0ff80", "dw::*");
+ DBG_OBJ_COLOR("#c0c0ff", "dw::fltk::*");
+ DBG_OBJ_COLOR("#ffa0a0", "dw::core::*");
+
uint_t opt_id;
uint_t options_got = 0;
uint32_t xid = 0;
diff --git a/src/form.cc b/src/form.cc
index 8476b73b..c5bb10af 100644
--- a/src/form.cc
+++ b/src/form.cc
@@ -340,7 +340,7 @@ void Html_tag_open_form(DilloHtml *html, const char *tag, int tagsize)
char *charset, *first;
const char *attrbuf;
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (9, html->wordStyle ());
if (html->InFlags & IN_FORM) {
BUG_MSG("nested forms\n");
@@ -567,7 +567,7 @@ void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize)
html->styleEngine->setNonCssHint (PROPERTY_X_TOOLTIP, CSS_TYPE_STRING,
attrbuf);
}
- HT2TB(html)->addWidget (embed, html->styleEngine->backgroundStyle());
+ HT2TB(html)->addWidget (embed, html->backgroundStyle());
}
dFree(type);
dFree(name);
@@ -600,17 +600,17 @@ void Html_tag_open_isindex(DilloHtml *html, const char *tag, int tagsize)
html->charset);
html->InFlags |= IN_FORM;
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (9, html->wordStyle ());
if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "prompt")))
- HT2TB(html)->addText(attrbuf, html->styleEngine->wordStyle ());
+ HT2TB(html)->addText(attrbuf, html->wordStyle ());
ResourceFactory *factory = HT2LT(html)->getResourceFactory();
EntryResource *entryResource = factory->createEntryResource (20,false,NULL);
embed = new Embed (entryResource);
Html_add_input(html, DILLO_HTML_INPUT_INDEX, embed, NULL, NULL, FALSE);
- HT2TB(html)->addWidget (embed, html->styleEngine->backgroundStyle ());
+ HT2TB(html)->addWidget (embed, html->backgroundStyle ());
a_Url_free(action);
html->InFlags &= ~IN_FORM;
@@ -675,7 +675,7 @@ void Html_tag_content_textarea(DilloHtml *html, const char *tag, int tagsize)
textres->setEditable(false);
Html_add_input(html, DILLO_HTML_INPUT_TEXTAREA, embed, name, NULL, false);
- HT2TB(html)->addWidget (embed, html->styleEngine->backgroundStyle ());
+ HT2TB(html)->addWidget (embed, html->backgroundStyle ());
dFree(name);
}
@@ -766,7 +766,7 @@ void Html_tag_open_select(DilloHtml *html, const char *tag, int tagsize)
html->styleEngine->setNonCssHint (PROPERTY_X_TOOLTIP, CSS_TYPE_STRING,
attrbuf);
}
- HT2TB(html)->addWidget (embed, html->styleEngine->backgroundStyle ());
+ HT2TB(html)->addWidget (embed, html->backgroundStyle ());
Html_add_input(html, type, embed, name, NULL, false);
a_Html_stash_init(html);
@@ -938,16 +938,16 @@ void Html_tag_open_button(DilloHtml *html, const char *tag, int tagsize)
* but it caused 100% CPU usage.
*/
page = new Textblock (false);
- page->setStyle (html->styleEngine->backgroundStyle ());
+ page->setStyle (html->backgroundStyle ());
ResourceFactory *factory = HT2LT(html)->getResourceFactory();
Resource *resource = factory->createComplexButtonResource(page, true);
embed = new Embed(resource);
// a_Dw_button_set_sensitive (DW_BUTTON (button), FALSE);
- HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ());
- HT2TB(html)->addWidget (embed, html->styleEngine->backgroundStyle ());
- HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (5, html->wordStyle ());
+ HT2TB(html)->addWidget (embed, html->backgroundStyle ());
+ HT2TB(html)->addParbreak (5, html->wordStyle ());
S_TOP(html)->textblock = html->dw = page;
@@ -2005,12 +2005,16 @@ static Embed *Html_input_image(DilloHtml *html, const char *tag, int tagsize)
/* create new image and add it to the button */
a_Html_image_attrs(html, tag, tagsize);
if ((Image = a_Html_image_new(html, tag, tagsize))) {
- IM2DW(Image)->setStyle (html->styleEngine->backgroundStyle ());
+ // At this point, we know that Image->ir represents an image
+ // widget. Notice that the order of the casts matters, because
+ // of multiple inheritance.
+ dw::Image *dwi = (dw::Image*)(dw::core::ImgRenderer*)Image->img_rndr;
+ dwi->setStyle (html->backgroundStyle ());
ResourceFactory *factory = HT2LT(html)->getResourceFactory();
ComplexButtonResource *complex_b_r =
- factory->createComplexButtonResource(IM2DW(Image), false);
+ factory->createComplexButtonResource(dwi, false);
button = new Embed(complex_b_r);
- HT2TB(html)->addWidget (button, html->styleEngine->style ());
+ HT2TB(html)->addWidget (button, html->style ());
}
if (!button)
MSG("Html_input_image: unable to create image submit.\n");
diff --git a/src/html.cc b/src/html.cc
index 46b502e5..74b90577 100644
--- a/src/html.cc
+++ b/src/html.cc
@@ -359,12 +359,11 @@ bool a_Html_tag_set_valign_attr(DilloHtml *html, const char *tag, int tagsize)
static void Html_add_textblock(DilloHtml *html, int space)
{
Textblock *textblock = new Textblock (prefs.limit_text_width);
- Style *style = html->styleEngine->style ();
- HT2TB(html)->addParbreak (space, html->styleEngine->wordStyle ());
- HT2TB(html)->addWidget (textblock, style); // Works also for floats etc.
-
- HT2TB(html)->addParbreak (space, html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (space, html->wordStyle ());
+ HT2TB(html)->addWidget (textblock, html->style ()); /* Works also for floats
+ etc. */
+ HT2TB(html)->addParbreak (space, html->wordStyle ());
S_TOP(html)->textblock = html->dw = textblock;
S_TOP(html)->hand_over_break = true;
}
@@ -1042,11 +1041,11 @@ static void Html_process_space_pre_line(DilloHtml *html, const char *space,
breakCnt++;
html->PrevWasCR = (space[i] == '\r');
- HT2TB(html)->addLinebreak (html->styleEngine->wordStyle ());
+ HT2TB(html)->addLinebreak (html->wordStyle ());
}
}
if (breakCnt == 0) {
- HT2TB(html)->addSpace(html->styleEngine->wordStyle ());
+ HT2TB(html)->addSpace(html->wordStyle ());
}
}
@@ -1079,12 +1078,11 @@ static void Html_process_space(DilloHtml *html, const char *space,
if (spaceCnt) {
spc = dStrnfill(spaceCnt, ' ');
- HT2TB(html)->addText (spc, spaceCnt,
- html->styleEngine->wordStyle ());
+ HT2TB(html)->addText (spc, spaceCnt, html->wordStyle ());
dFree(spc);
spaceCnt = 0;
}
- HT2TB(html)->addLinebreak (html->styleEngine->wordStyle ());
+ HT2TB(html)->addLinebreak (html->wordStyle ());
html->pre_column = 0;
}
html->PreFirstChar = false;
@@ -1112,20 +1110,19 @@ static void Html_process_space(DilloHtml *html, const char *space,
if (spaceCnt) {
// add break possibility for the white-space:pre-wrap case
- HT2TB(html)->addBreakOption (html->styleEngine->wordStyle (), false);
+ HT2TB(html)->addBreakOption (html->wordStyle (), false);
spc = dStrnfill(spaceCnt, ' ');
- HT2TB(html)->addText (spc, spaceCnt, html->styleEngine->wordStyle ());
+ HT2TB(html)->addText (spc, spaceCnt, html->wordStyle ());
dFree(spc);
}
} else {
if (SGML_SPCDEL) {
/* SGML_SPCDEL ignores white space immediately after an open tag */
- } else if (html->styleEngine->wordStyle ()->whiteSpace ==
- WHITE_SPACE_PRE_LINE) {
+ } else if (html->wordStyle ()->whiteSpace == WHITE_SPACE_PRE_LINE) {
Html_process_space_pre_line(html, space, spacesize);
} else {
- HT2TB(html)->addSpace(html->styleEngine->wordStyle ());
+ HT2TB(html)->addSpace(html->wordStyle ());
}
if (parse_mode == DILLO_HTML_PARSE_MODE_STASH_AND_BODY)
@@ -1178,8 +1175,7 @@ static void Html_process_word(DilloHtml *html, const char *word, int size)
Html_process_space(html, Pword + start, i - start);
} else {
while (Pword[++i] && !isspace(Pword[i])) ;
- HT2TB(html)->addText(Pword + start, i - start,
- html->styleEngine->wordStyle ());
+ HT2TB(html)->addText(Pword + start, i - start, html->wordStyle ());
html->pre_column += i - start;
html->PreFirstChar = false;
}
@@ -1217,20 +1213,18 @@ static void Html_process_word(DilloHtml *html, const char *word, int size)
Html_process_space(html, word2 + start, i - start);
} else if (!strncmp(word2+i, utf8_zero_width_space, 3)) {
i += 3;
- HT2TB(html)->addBreakOption(html->styleEngine->wordStyle (), false);
+ HT2TB(html)->addBreakOption(html->wordStyle (), false);
} else if (a_Utf8_ideographic(word2+i, beyond_word2, &len)) {
i += len;
- HT2TB(html)->addText(word2 + start, i - start,
- html->styleEngine->wordStyle ());
- HT2TB(html)->addBreakOption(html->styleEngine->wordStyle (), false);
+ HT2TB(html)->addText(word2 + start, i - start, html->wordStyle ());
+ HT2TB(html)->addBreakOption(html->wordStyle (), false);
} else {
do {
i += len;
} while (word2[i] && !isspace(word2[i]) &&
strncmp(word2+i, utf8_zero_width_space, 3) &&
(!a_Utf8_ideographic(word2+i, beyond_word2, &len)));
- HT2TB(html)->addText(word2 + start, i - start,
- html->styleEngine->wordStyle ());
+ HT2TB(html)->addText(word2 + start, i - start, html->wordStyle ());
}
}
if (Pword == word2)
@@ -1264,7 +1258,7 @@ static void Html_eventually_pop_dw(DilloHtml *html, bool hand_over_break)
{
if (html->dw != S_TOP(html)->textblock) {
if (hand_over_break)
- HT2TB(html)->handOverBreak (html->styleEngine->style ());
+ HT2TB(html)->handOverBreak (html->style ());
HT2TB(html)->flush ();
html->dw = S_TOP(html)->textblock;
}
@@ -1292,7 +1286,7 @@ static void Html_push_tag(DilloHtml *html, int tag_idx)
*/
static void Html_force_push_tag(DilloHtml *html, int tag_idx)
{
- html->styleEngine->startElement (tag_idx);
+ html->startElement (tag_idx);
Html_push_tag(html, tag_idx);
}
@@ -1818,6 +1812,10 @@ static void Html_tag_open_body(DilloHtml *html, const char *tag, int tagsize)
int32_t color;
int tag_index_a = a_Html_tag_index ("a");
style::Color *bgColor;
+ style::StyleImage *bgImage;
+ style::BackgroundRepeat bgRepeat;
+ style::BackgroundAttachment bgAttachment;
+ style::Length bgPositionX, bgPositionY;
_MSG("Html_tag_open_body Num_BODY=%d\n", html->Num_BODY);
if (!(html->InFlags & IN_BODY))
@@ -1858,7 +1856,7 @@ static void Html_tag_open_body(DilloHtml *html, const char *tag, int tagsize)
CSS_TYPE_COLOR, color);
}
- html->styleEngine->restyle ();
+ html->restyle ();
if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "link"))) {
html->non_css_link_color = a_Html_color_parse(html, attrbuf, -1);
@@ -1872,35 +1870,40 @@ static void Html_tag_open_body(DilloHtml *html, const char *tag, int tagsize)
BUG_MSG("<body> vlink attribute is obsolete.\n");
}
- html->dw->setStyle (html->styleEngine->style ());
+ html->dw->setStyle (html->style ());
bgColor = html->styleEngine->backgroundColor ();
-
if (bgColor)
HT2LT(html)->setBgColor(bgColor);
+ bgImage = html->styleEngine->backgroundImage (&bgRepeat, &bgAttachment,
+ &bgPositionX, &bgPositionY);
+ if (bgImage)
+ HT2LT(html)->setBgImage(bgImage, bgRepeat, bgAttachment, bgPositionX,
+ bgPositionY);
+
/* Determine a color for visited links.
* This color is computed once per page and used for immediate feedback
* when clicking a link.
* On reload style including color for visited links is computed properly
* according to CSS.
*/
- html->styleEngine->startElement (tag_index_a);
+ html->startElement (tag_index_a);
html->styleEngine->setPseudoVisited ();
if (html->non_css_visited_color != -1) {
html->styleEngine->setNonCssHint (CSS_PROPERTY_COLOR, CSS_TYPE_COLOR,
html->non_css_visited_color);
}
- html->visited_color = html->styleEngine->style ()->color->getColor ();
+ html->visited_color = html->style ()->color->getColor ();
html->styleEngine->endElement (tag_index_a);
if (prefs.contrast_visited_color) {
/* get a color that has a "safe distance" from text, link and bg */
html->visited_color =
a_Color_vc(html->visited_color,
- html->styleEngine->style ()->color->getColor(),
+ html->style ()->color->getColor(),
html->non_css_link_color,
- html->styleEngine->backgroundStyle()->backgroundColor->getColor());
+ html->backgroundStyle()->backgroundColor->getColor());
}
@@ -1972,28 +1975,28 @@ static void
src = dStrdup(attrbuf);
- textblock->addParbreak (5, html->styleEngine->wordStyle ());
+ textblock->addParbreak (5, html->wordStyle ());
bullet = new Bullet();
- textblock->addWidget(bullet, html->styleEngine->wordStyle ());
- textblock->addSpace(html->styleEngine->wordStyle ());
+ textblock->addWidget(bullet, html->wordStyle ());
+ textblock->addSpace(html->wordStyle ());
if (D_ASCII_TOLOWER(tag[1]) == 'i') {
/* IFRAME usually comes with very long advertising/spying URLS,
* to not break rendering we will force name="IFRAME" */
- textblock->addText ("IFRAME", html->styleEngine->wordStyle ());
+ textblock->addText ("IFRAME", html->wordStyle ());
} else {
/* FRAME:
* If 'name' tag is present use it, if not use 'src' value */
if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "name"))) {
- textblock->addText (src, html->styleEngine->wordStyle ());
+ textblock->addText (src, html->wordStyle ());
} else {
- textblock->addText (attrbuf, html->styleEngine->wordStyle ());
+ textblock->addText (attrbuf, html->wordStyle ());
}
}
- textblock->addParbreak (5, html->styleEngine->wordStyle ());
+ textblock->addParbreak (5, html->wordStyle ());
dFree(src);
}
@@ -2006,8 +2009,8 @@ static void
static void Html_tag_content_frameset (DilloHtml *html,
const char *tag, int tagsize)
{
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
- HT2TB(html)->addText("--FRAME--", html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (9, html->wordStyle ());
+ HT2TB(html)->addText("--FRAME--", html->wordStyle ());
Html_add_textblock(html, 5);
}
@@ -2028,7 +2031,7 @@ static void Html_tag_open_h(DilloHtml *html, const char *tag, int tagsize)
*/
static void Html_tag_content_br(DilloHtml *html, const char *tag, int tagsize)
{
- HT2TB(html)->addLinebreak (html->styleEngine->wordStyle ());
+ HT2TB(html)->addLinebreak (html->wordStyle ());
}
/*
@@ -2217,7 +2220,9 @@ DilloImage *a_Html_image_new(DilloHtml *html, const char *tag, int tagsize)
alt_ptr = dStrdup("[IMG]"); // Place holder for img_off mode
}
- image = a_Image_new(alt_ptr, 0);
+ dw::Image *dw = new dw::Image(alt_ptr);
+ image =
+ a_Image_new(html->dw->getLayout(), (void*)(dw::core::ImgRenderer*)dw, 0);
if (HT2TB(html)->getBgColor())
image->bg_color = HT2TB(html)->getBgColor()->getColor();
@@ -2294,13 +2299,17 @@ static void Html_tag_content_img(DilloHtml *html, const char *tag, int tagsize)
/* TODO: usemap URLs outside of the document are not used. */
usemap_url = a_Html_url_new(html, attrbuf, NULL, 0);
- HT2TB(html)->addWidget((Widget*)Image->dw, html->styleEngine->style());
+ // At this point, we know that Image->ir represents an image
+ // widget. Notice that the order of the casts matters, because of
+ // multiple inheritance.
+ dw::Image *dwi = (dw::Image*)(dw::core::ImgRenderer*)Image->img_rndr;
+ HT2TB(html)->addWidget(dwi, html->style());
/* Image maps */
if (a_Html_get_attr(html, tag, tagsize, "ismap")) {
- ((::dw::Image*)Image->dw)->setIsMap();
+ dwi->setIsMap();
_MSG(" Html_tag_open_img: server-side map (ISMAP)\n");
- } else if (html->styleEngine->style ()->x_link != -1 &&
+ } else if (html->style ()->x_link != -1 &&
usemap_url == NULL) {
/* For simple links, we have to suppress the "image_pressed" signal.
* This is overridden for USEMAP images. */
@@ -2308,8 +2317,7 @@ static void Html_tag_content_img(DilloHtml *html, const char *tag, int tagsize)
}
if (usemap_url) {
- ((::dw::Image*)Image->dw)->setUseMap(&html->maps,
- new ::object::String(URL_STR(usemap_url)));
+ dwi->setUseMap(&html->maps, new ::object::String(URL_STR(usemap_url)));
a_Url_free (usemap_url);
}
}
@@ -2352,8 +2360,14 @@ static void Html_tag_close_map(DilloHtml *html)
for (int i = 0; i < html->images->size(); i++) {
DilloImage *img = html->images->get(i)->image;
- if (img)
- ((dw::Image*) img->dw)->forceMapRedraw();
+ if (img) {
+ // At this point, we know that img->ir represents an image
+ // widget. (Really? Is this assumtion safe?) Notice that the
+ // order of the casts matters, because of multiple
+ // inheritance.
+ dw::Image *dwi = (dw::Image*)(dw::core::ImgRenderer*)img->img_rndr;
+ dwi->forceMapRedraw();
+ }
}
html->InFlags &= ~IN_MAP;
}
@@ -2496,7 +2510,7 @@ static void Html_tag_open_object(DilloHtml *html, const char *tag, int tagsize)
html->styleEngine->setNonCssHint(PROPERTY_X_LINK, CSS_TYPE_INTEGER,
Html_set_new_link(html, &url));
- HT2TB(html)->addText("[OBJECT]", html->styleEngine->wordStyle ());
+ HT2TB(html)->addText("[OBJECT]", html->wordStyle ());
}
a_Url_free(base_url);
}
@@ -2530,7 +2544,7 @@ static const char* Html_get_javascript_link(DilloHtml *html)
static void Html_add_anchor(DilloHtml *html, const char *name)
{
_MSG("Registering ANCHOR: %s\n", name);
- if (!HT2TB(html)->addAnchor (name, html->styleEngine->style ()))
+ if (!HT2TB(html)->addAnchor (name, html->style ()))
BUG_MSG("Anchor names must be unique within the document ('%s')\n",name);
/*
* According to Sec. 12.2.1 of the HTML 4.01 spec, "anchor names that
@@ -2639,7 +2653,7 @@ static void Html_tag_open_q(DilloHtml *html, const char *tag, int tagsize)
const char *U201C = "\xe2\x80\x9c";
html->styleEngine->inheritBackgroundColor ();
- HT2TB(html)->addText (U201C, html->styleEngine->wordStyle ());
+ HT2TB(html)->addText (U201C, html->wordStyle ());
}
/*
@@ -2650,7 +2664,7 @@ static void Html_tag_close_q(DilloHtml *html)
/* Right Double Quotation Mark */
const char *U201D = "\xe2\x80\x9d";
- HT2TB(html)->addText (U201D, html->styleEngine->wordStyle ());
+ HT2TB(html)->addText (U201D, html->wordStyle ());
}
/*
@@ -2692,7 +2706,7 @@ static void Html_tag_open_ul(DilloHtml *html, const char *tag, int tagsize)
static void Html_tag_open_dir(DilloHtml *html, const char *tag, int tagsize)
{
html->styleEngine->inheritBackgroundColor ();
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (9, html->wordStyle ());
S_TOP(html)->list_type = HTML_LIST_UNORDERED;
S_TOP(html)->list_number = 0;
@@ -2752,7 +2766,7 @@ static void Html_tag_open_ol(DilloHtml *html, const char *tag, int tagsize)
*/
static void Html_tag_open_li(DilloHtml *html, const char *tag, int tagsize)
{
- Style *style = html->styleEngine->style ();
+ Style *style = html->style ();
int *list_number;
const char *attrbuf;
@@ -2847,12 +2861,12 @@ static void Html_tag_open_hr(DilloHtml *html, const char *tag, int tagsize)
static void Html_tag_content_hr(DilloHtml *html, const char *tag, int tagsize)
{
Widget *hruler;
- HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (5, html->wordStyle ());
hruler = new Ruler();
- hruler->setStyle (html->styleEngine->style ());
- HT2TB(html)->addWidget (hruler, html->styleEngine->style ());
- HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ());
+ hruler->setStyle (html->style ());
+ HT2TB(html)->addWidget (hruler, html->style ());
+ HT2TB(html)->addParbreak (5, html->wordStyle ());
}
/*
@@ -2862,7 +2876,7 @@ static void Html_tag_open_dl(DilloHtml *html, const char *tag, int tagsize)
{
/* may want to actually do some stuff here. */
html->styleEngine->inheritBackgroundColor ();
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (9, html->wordStyle ());
}
/*
@@ -2871,7 +2885,7 @@ static void Html_tag_open_dl(DilloHtml *html, const char *tag, int tagsize)
static void Html_tag_open_dt(DilloHtml *html, const char *tag, int tagsize)
{
html->styleEngine->inheritBackgroundColor ();
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (9, html->wordStyle ());
}
/*
@@ -2888,7 +2902,7 @@ static void Html_tag_open_dd(DilloHtml *html, const char *tag, int tagsize)
static void Html_tag_open_pre(DilloHtml *html, const char *tag, int tagsize)
{
html->styleEngine->inheritBackgroundColor ();
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (9, html->wordStyle ());
html->InFlags |= IN_PRE;
}
@@ -3220,7 +3234,7 @@ static void Html_tag_open_div(DilloHtml *html, const char *tag, int tagsize)
*/
static void Html_tag_close_par(DilloHtml *html)
{
- HT2TB(html)->addParbreak (9, html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (9, html->wordStyle ());
}
/*
@@ -3228,7 +3242,7 @@ static void Html_tag_close_par(DilloHtml *html)
*/
static void Html_tag_content_wbr(DilloHtml *html, const char *tag, int tagsize)
{
- HT2TB(html)->addBreakOption(html->styleEngine->wordStyle (), true);
+ HT2TB(html)->addBreakOption(html->wordStyle (), true);
}
@@ -3663,8 +3677,8 @@ static void Html_display_block(DilloHtml *html)
static void Html_display_listitem(DilloHtml *html)
{
- Style *style = html->styleEngine->style ();
- Style *wordStyle = html->styleEngine->wordStyle ();
+ Style *style = html->style ();
+ Style *wordStyle = html->wordStyle ();
Widget **ref_list_item;
ListItem *list_item;
int *list_number;
@@ -3748,7 +3762,7 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize)
/* Push the tag into the stack */
Html_push_tag(html, ni);
- html->styleEngine->startElement (ni);
+ html->startElement (ni);
_MSG("Open : %*s%s\n", html->stack->size(), " ", Tags[ni].name);
/* Parse attributes that can appear on any tag */
@@ -3759,7 +3773,7 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize)
Tags[ni].open (html, tag, tagsize);
if (! S_TOP(html)->display_none) {
- switch (html->styleEngine->style ()->display) {
+ switch (html->style ()->display) {
case DISPLAY_BLOCK:
Html_display_block(html);
break;
@@ -3786,8 +3800,8 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize)
if (S_TOP(html)->parse_mode == DILLO_HTML_PARSE_MODE_VERBATIM) {
/* don't change anything */
} else if (S_TOP(html)->parse_mode != DILLO_HTML_PARSE_MODE_PRE &&
- (html->styleEngine->style ()->whiteSpace == WHITE_SPACE_PRE ||
- html->styleEngine->style ()->whiteSpace == WHITE_SPACE_PRE_WRAP)) {
+ (html->style ()->whiteSpace == WHITE_SPACE_PRE ||
+ html->style ()->whiteSpace == WHITE_SPACE_PRE_WRAP)) {
S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_PRE;
html->pre_column = 0;
html->PreFirstChar = true;
diff --git a/src/html_common.hh b/src/html_common.hh
index 6c5d4807..a43d91b7 100644
--- a/src/html_common.hh
+++ b/src/html_common.hh
@@ -218,6 +218,22 @@ public:
bool_t unloadedImages();
void loadImages (const DilloUrl *pattern);
void addCssUrl(const DilloUrl *url);
+
+ // useful shortcuts
+ inline void startElement (int tag)
+ { styleEngine->startElement (tag, bw, base_url); }
+ inline void startElement (const char *tagname)
+ { styleEngine->startElement (tagname, bw, base_url); }
+
+ inline dw::core::style::Style *backgroundStyle ()
+ { return styleEngine->backgroundStyle (bw, base_url); }
+ inline dw::core::style::Style *style ()
+ { return styleEngine->style (bw, base_url); }
+ inline dw::core::style::Style *wordStyle ()
+ { return styleEngine->wordStyle (bw, base_url); }
+
+ inline void restyle () { styleEngine->restyle (bw, base_url); }
+
};
/*
diff --git a/src/image.cc b/src/image.cc
index c499d977..9915023a 100644
--- a/src/image.cc
+++ b/src/image.cc
@@ -23,19 +23,20 @@
using namespace dw::core;
-// Image to Object-Image macro
-#define I2DW(Image) ((dw::Image*)(Image->dw))
+// Image to Object-ImgRenderer macro
+#define I2IR(Image) ((dw::core::ImgRenderer*)(Image->img_rndr))
/*
* Create and initialize a new image structure.
*/
-DilloImage *a_Image_new(const char *alt_text, int32_t bg_color)
+DilloImage *a_Image_new(void *layout, void *img_rndr, int32_t bg_color)
{
DilloImage *Image;
Image = dNew(DilloImage, 1);
- Image->dw = (void*) new dw::Image(alt_text);
+ Image->layout = layout;
+ Image->img_rndr = img_rndr;
Image->width = 0;
Image->height = 0;
Image->bg_color = bg_color;
@@ -49,6 +50,26 @@ DilloImage *a_Image_new(const char *alt_text, int32_t bg_color)
}
/*
+ * Create and initialize a new image structure with an image widget.
+ */
+DilloImage *a_Image_new_with_dw(void *layout, const char *alt_text,
+ int32_t bg_color)
+{
+ dw::Image *dw = new dw::Image(alt_text);
+ return a_Image_new(layout, (void*)(dw::core::ImgRenderer*)dw, bg_color);
+}
+
+/*
+ * Return the image renderer as a widget. This is somewhat tricky,
+ * since simple casting leads to wrong (and hard to debug) results,
+ * because of multiple inheritance. This function can be used from C
+ * code, where only access to void* is possible.
+ */
+void *a_Image_get_dw(DilloImage *Image)
+{
+ return (dw::Image*)(dw::core::ImgRenderer*)Image->img_rndr;
+}
+/*
* Deallocate an Image structure
*/
static void Image_free(DilloImage *Image)
@@ -88,7 +109,7 @@ void a_Image_set_parms(DilloImage *Image, void *v_imgbuf, DilloUrl *url,
_MSG("a_Image_set_parms: width=%d height=%d\n", width, height);
bool resize = (Image->width != width || Image->height != height);
- I2DW(Image)->setBuffer((Imgbuf*)v_imgbuf, resize);
+ I2IR(Image)->setBuffer((Imgbuf*)v_imgbuf, resize);
if (!Image->BitVec)
Image->BitVec = a_Bitvec_new(height);
@@ -106,7 +127,7 @@ void a_Image_write(DilloImage *Image, uint_t y)
dReturn_if_fail ( y < Image->height );
/* Update the row in DwImage */
- I2DW(Image)->drawRow(y);
+ I2IR(Image)->drawRow(y);
a_Bitvec_set_bit(Image->BitVec, y);
Image->State = IMG_Write;
}
@@ -117,5 +138,15 @@ void a_Image_write(DilloImage *Image, uint_t y)
void a_Image_close(DilloImage *Image)
{
_MSG("a_Image_close\n");
+ I2IR(Image)->finish();
+}
+
+/*
+ * Implement the abort method
+ */
+void a_Image_abort(DilloImage *Image)
+{
+ _MSG("a_Image_abort\n");
+ I2IR(Image)->fatal();
}
diff --git a/src/image.hh b/src/image.hh
index a66edaae..39fe0405 100644
--- a/src/image.hh
+++ b/src/image.hh
@@ -44,7 +44,7 @@ typedef enum {
} ImageState;
struct _DilloImage {
- void *dw;
+ void *layout, *img_rndr;
/* Parameters as told by image data */
uint_t width;
@@ -62,7 +62,10 @@ struct _DilloImage {
/*
* Function prototypes
*/
-DilloImage *a_Image_new(const char *alt_text, int32_t bg_color);
+DilloImage *a_Image_new(void *layout, void *img_rndr, int32_t bg_color);
+DilloImage *a_Image_new_with_dw(void *layout, const char *alt_text,
+ int32_t bg_color);
+void *a_Image_get_dw(DilloImage *Image);
void a_Image_ref(DilloImage *Image);
void a_Image_unref(DilloImage *Image);
@@ -71,6 +74,7 @@ void a_Image_set_parms(DilloImage *Image, void *v_imgbuf, DilloUrl *url,
DilloImgType type);
void a_Image_write(DilloImage *Image, uint_t y);
void a_Image_close(DilloImage *Image);
+void a_Image_abort(DilloImage *Image);
#ifdef __cplusplus
diff --git a/src/imgbuf.cc b/src/imgbuf.cc
index 16eb5c31..48e6bde5 100644
--- a/src/imgbuf.cc
+++ b/src/imgbuf.cc
@@ -90,10 +90,9 @@ void a_Imgbuf_unref(void *v_imgbuf)
/*
* Create a new Imgbuf
*/
-void *a_Imgbuf_new(void *v_dw, int img_type, uint_t width, uint_t height,
+void *a_Imgbuf_new(void *layout, int img_type, uint_t width, uint_t height,
double gamma)
{
- Layout *layout = ((Widget*)v_dw)->getLayout();
if (!layout) {
MSG_ERR("a_Imgbuf_new: layout is NULL.\n");
exit(1);
@@ -104,7 +103,8 @@ void *a_Imgbuf_new(void *v_dw, int img_type, uint_t width, uint_t height,
linebuf = (uchar_t*) dRealloc(linebuf, linebuf_size);
}
- return (void*)layout->createImgbuf(Imgbuf::RGB, width, height, gamma);
+ return (void*)((Layout*)layout)->createImgbuf(Imgbuf::RGB, width, height,
+ gamma);
}
/*
diff --git a/src/imgbuf.hh b/src/imgbuf.hh
index af0bf9a6..efa1b48c 100644
--- a/src/imgbuf.hh
+++ b/src/imgbuf.hh
@@ -16,7 +16,7 @@ extern "C" {
*/
void a_Imgbuf_ref(void *v_imgbuf);
void a_Imgbuf_unref(void *v_imgbuf);
-void *a_Imgbuf_new(void *v_dw, int img_type, uint_t width, uint_t height,
+void *a_Imgbuf_new(void *v_ir, int img_type, uint_t width, uint_t height,
double gamma);
int a_Imgbuf_last_reference(void *v_imgbuf);
void a_Imgbuf_update(void *v_imgbuf, const uchar_t *buf, DilloImgType type,
diff --git a/src/menu.cc b/src/menu.cc
index 617297ce..b93106e1 100644
--- a/src/menu.cc
+++ b/src/menu.cc
@@ -679,6 +679,18 @@ static void Menu_imgload_toggle_cb(Fl_Widget *wid, void*)
}
/*
+ * Toggle loading of background images.
+ */
+static void Menu_bgimg_load_toggle_cb(Fl_Widget *wid, void*)
+{
+ Fl_Menu_Item *item = (Fl_Menu_Item*) wid;
+
+ item->flags ^= FL_MENU_VALUE;
+ prefs.load_background_images = item->flags & FL_MENU_VALUE ? 1 : 0;
+ a_UIcmd_repush(popup_bw);
+}
+
+/*
* Tools popup menu (construction & popup)
*/
void a_Menu_tools_popup(BrowserWindow *bw, int x, int y)
@@ -691,6 +703,8 @@ void a_Menu_tools_popup(BrowserWindow *bw, int x, int y)
{"Use embedded CSS", 0, Menu_embedded_css_cb, 0,
FL_MENU_TOGGLE|FL_MENU_DIVIDER,0,0,0,0},
{"Load images", 0, Menu_imgload_toggle_cb, 0,
+ FL_MENU_TOGGLE,0,0,0,0},
+ {"Load background images", 0, Menu_bgimg_load_toggle_cb, 0,
FL_MENU_TOGGLE|FL_MENU_DIVIDER,0,0,0,0},
{"Panel size", 0, Menu_nop_cb, (void*)"Submenu1", FL_SUBMENU,0,0,0,0},
{"tiny", 0,Menu_panel_change_cb,(void*)0,FL_MENU_RADIO,0,0,0,0},
@@ -713,8 +727,10 @@ void a_Menu_tools_popup(BrowserWindow *bw, int x, int y)
pm[1].set();
if (prefs.load_images)
pm[2].set();
- pm[4+cur_panelsize].setonly();
- cur_smallicons ? pm[7].set() : pm[7].clear();
+ if (prefs.load_background_images)
+ pm[3].set();
+ pm[5+cur_panelsize].setonly();
+ cur_smallicons ? pm[8].set() : pm[8].clear();
item = pm->popup(x, y);
if (item) {
diff --git a/src/plain.cc b/src/plain.cc
index d63ce6cf..d09f6d79 100644
--- a/src/plain.cc
+++ b/src/plain.cc
@@ -97,9 +97,10 @@ DilloPlain::DilloPlain(BrowserWindow *p_bw)
Layout *layout = (Layout*) bw->render_layout;
StyleEngine styleEngine (layout);
- styleEngine.startElement ("body");
- styleEngine.startElement ("pre");
- widgetStyle = styleEngine.wordStyle ();
+ // TODO (3x) No URL?
+ styleEngine.startElement ("body", bw, NULL);
+ styleEngine.startElement ("pre", bw, NULL);
+ widgetStyle = styleEngine.wordStyle (bw, NULL);
widgetStyle->ref ();
/* The context menu */
diff --git a/src/prefs.c b/src/prefs.c
index a192c324..257e4a05 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -68,6 +68,7 @@ void a_Prefs_init(void)
prefs.http_user_agent = dStrdup(PREFS_HTTP_USER_AGENT);
prefs.limit_text_width = FALSE;
prefs.load_images=TRUE;
+ prefs.load_background_images=TRUE;
prefs.load_stylesheets=TRUE;
prefs.middle_click_drags_page = TRUE;
prefs.middle_click_opens_new_tab = TRUE;
diff --git a/src/prefs.h b/src/prefs.h
index de3e0342..bb97651e 100644
--- a/src/prefs.h
+++ b/src/prefs.h
@@ -88,6 +88,7 @@ typedef struct {
bool_t show_quit_dialog;
bool_t fullwindow_start;
bool_t load_images;
+ bool_t load_background_images;
bool_t load_stylesheets;
bool_t parse_embedded_css;
int32_t buffered_drawing;
diff --git a/src/prefsparser.cc b/src/prefsparser.cc
index 86f8580c..81b097e7 100644
--- a/src/prefsparser.cc
+++ b/src/prefsparser.cc
@@ -79,6 +79,7 @@ int PrefsParser::parseOption(char *name, char *value)
{ "http_user_agent", &prefs.http_user_agent, PREFS_STRING },
{ "limit_text_width", &prefs.limit_text_width, PREFS_BOOL },
{ "load_images", &prefs.load_images, PREFS_BOOL },
+ { "load_background_images", &prefs.load_background_images, PREFS_BOOL },
{ "load_stylesheets", &prefs.load_stylesheets, PREFS_BOOL },
{ "middle_click_drags_page", &prefs.middle_click_drags_page,
PREFS_BOOL },
diff --git a/src/styleengine.cc b/src/styleengine.cc
index 8817479f..2da9d8f7 100644
--- a/src/styleengine.cc
+++ b/src/styleengine.cc
@@ -15,10 +15,49 @@
#include "misc.h"
#include "html_common.hh"
#include "styleengine.hh"
+#include "web.hh"
+#include "capi.h"
using namespace lout::misc;
using namespace dw::core::style;
+/**
+ * Signal handler for "delete": This handles the case when an instance
+ * of StyleImage is deleted, possibly when the cache client is still
+ * active.
+ *
+ * \todo Not neccessary for dw::Image? (dw::Image also implements
+ * lout::signal::ObservedObject.)
+ */
+class StyleImageDeletionReceiver:
+ public lout::signal::ObservedObject::DeletionReceiver
+{
+ int clientKey;
+
+public:
+ StyleImageDeletionReceiver (int clientKey);
+ ~StyleImageDeletionReceiver ();
+
+ void deleted (lout::signal::ObservedObject *object);
+};
+
+StyleImageDeletionReceiver::StyleImageDeletionReceiver (int clientKey)
+{
+ this->clientKey = clientKey;
+}
+
+StyleImageDeletionReceiver::~StyleImageDeletionReceiver ()
+{
+}
+
+void StyleImageDeletionReceiver::deleted (lout::signal::ObservedObject *object)
+{
+ a_Capi_stop_client (clientKey, 0);
+ delete this;
+}
+
+// ----------------------------------------------------------------------
+
StyleEngine::StyleEngine (dw::core::Layout *layout) {
StyleAttrs style_attrs;
FontAttrs font_attrs;
@@ -92,8 +131,8 @@ void StyleEngine::stackPop () {
/**
* \brief tell the styleEngine that a new html element has started.
*/
-void StyleEngine::startElement (int element) {
- style (); // ensure that style of current node is computed
+void StyleEngine::startElement (int element, BrowserWindow *bw, DilloUrl *url) {
+ style (bw, url); // ensure that style of current node is computed
stackPush ();
Node *n = stack->getLastRef ();
@@ -103,8 +142,9 @@ void StyleEngine::startElement (int element) {
n->doctreeNode = dn;
}
-void StyleEngine::startElement (const char *tagname) {
- startElement (a_Html_tag_index (tagname));
+void StyleEngine::startElement (const char *tagname, BrowserWindow *bw,
+ DilloUrl *url) {
+ startElement (a_Html_tag_index (tagname), bw, url);
}
void StyleEngine::setId (const char *id) {
@@ -207,6 +247,26 @@ dw::core::style::Color *StyleEngine::backgroundColor () {
return NULL;
}
+dw::core::style::StyleImage *StyleEngine::backgroundImage
+ (dw::core::style::BackgroundRepeat *bgRepeat,
+ dw::core::style::BackgroundAttachment *bgAttachment,
+ dw::core::style::Length *bgPositionX,
+ dw::core::style::Length *bgPositionY) {
+ for (int i = 1; i < stack->size (); i++) {
+ Node *n = stack->getRef (i);
+
+ if (n->style && n->style->backgroundImage) {
+ *bgRepeat = n->style->backgroundRepeat;
+ *bgAttachment = n->style->backgroundAttachment;
+ *bgPositionX = n->style->backgroundPositionX;
+ *bgPositionY = n->style->backgroundPositionY;
+ return n->style->backgroundImage;
+ }
+ }
+
+ return NULL;
+}
+
/**
* \brief set the CSS pseudo class :link.
*/
@@ -238,6 +298,16 @@ void StyleEngine::preprocessAttrs (dw::core::style::StyleAttrs *attrs) {
if (stack->getRef (stack->size () - 2)->inheritBackgroundColor) {
attrs->backgroundColor =
stack->getRef (stack->size () - 2)->style->backgroundColor;
+ attrs->backgroundImage =
+ stack->getRef (stack->size () - 2)->style->backgroundImage;
+ attrs->backgroundRepeat =
+ stack->getRef (stack->size () - 2)->style->backgroundRepeat;
+ attrs->backgroundAttachment =
+ stack->getRef (stack->size () - 2)->style->backgroundAttachment;
+ attrs->backgroundPositionX =
+ stack->getRef (stack->size () - 2)->style->backgroundPositionX;
+ attrs->backgroundPositionY =
+ stack->getRef (stack->size () - 2)->style->backgroundPositionY;
attrs->valign = stack->getRef (stack->size () - 2)->style->valign;
}
@@ -281,7 +351,8 @@ void StyleEngine::postprocessAttrs (dw::core::style::StyleAttrs *attrs) {
/**
* \brief Make changes to StyleAttrs attrs according to CssPropertyList props.
*/
-void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props) {
+void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props,
+ BrowserWindow *bw, DilloUrl *url) {
FontAttrs fontAttrs = *attrs->font;
Font *parentFont = stack->get (i - 1).style->font;
char *c, *fontName;
@@ -441,6 +512,10 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props) {
switch (p->name) {
/* \todo missing cases */
+ case CSS_PROPERTY_BACKGROUND_ATTACHMENT:
+ attrs->backgroundAttachment =
+ (BackgroundAttachment) p->value.intVal;
+ break;
case CSS_PROPERTY_BACKGROUND_COLOR:
if (prefs.allow_white_bg || p->value.intVal != 0xffffff)
attrs->backgroundColor = Color::create(layout, p->value.intVal);
@@ -448,6 +523,42 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props) {
attrs->backgroundColor =
Color::create(layout, prefs.white_bg_replacement);
break;
+ case CSS_PROPERTY_BACKGROUND_IMAGE:
+ if (prefs.load_background_images)
+ {
+ DilloUrl *imgUrl =
+ a_Url_new (p->value.strVal, a_Url_str (url));
+
+ attrs->backgroundImage = StyleImage::create();
+ DilloImage *image =
+ a_Image_new(layout,
+ (void*)attrs->backgroundImage
+ ->getMainImgRenderer(),
+ 0xffffff);
+
+ DilloWeb *web = a_Web_new(bw, imgUrl, url);
+ web->Image = image;
+ a_Image_ref(image);
+ web->flags |= WEB_Image;
+
+ int clientKey;
+ if ((clientKey = a_Capi_open_url(web, NULL, NULL)) != 0) {
+ a_Bw_add_client(bw, clientKey, 0);
+ a_Bw_add_url(bw, url);
+ attrs->backgroundImage->connectDeletion
+ (new StyleImageDeletionReceiver (clientKey));
+ }
+ }
+ break;
+ case CSS_PROPERTY_BACKGROUND_POSITION:
+ computeLength (&attrs->backgroundPositionX, p->value.posVal->posX,
+ attrs->font);
+ computeLength (&attrs->backgroundPositionY, p->value.posVal->posY,
+ attrs->font);
+ break;
+ case CSS_PROPERTY_BACKGROUND_REPEAT:
+ attrs->backgroundRepeat = (BackgroundRepeat) p->value.intVal;
+ break;
case CSS_PROPERTY_BORDER_COLLAPSE:
attrs->borderCollapse = (BorderCollapse) p->value.intVal;
break;
@@ -727,9 +838,9 @@ void StyleEngine::computeBorderWidth (int *dest, CssProperty *p,
* A normal style might have backgroundColor == NULL to indicate a transparent
* background. This method ensures that backgroundColor is set.
*/
-Style * StyleEngine::backgroundStyle () {
+Style * StyleEngine::backgroundStyle (BrowserWindow *bw, DilloUrl *url) {
if (!stack->getRef (stack->size () - 1)->backgroundStyle) {
- StyleAttrs attrs = *style ();
+ StyleAttrs attrs = *style (bw, url);
for (int i = stack->size () - 1; i >= 0 && ! attrs.backgroundColor; i--)
attrs.backgroundColor = stack->getRef (i)->style->backgroundColor;
@@ -746,7 +857,7 @@ Style * StyleEngine::backgroundStyle () {
* HTML elements and the nonCssProperties that have been set.
* This method is private. Call style() to get a current style object.
*/
-Style * StyleEngine::style0 (int i) {
+Style * StyleEngine::style0 (int i, BrowserWindow *bw, DilloUrl *url) {
CssPropertyList props, *styleAttrProperties, *styleAttrPropertiesImportant;
CssPropertyList *nonCssProperties;
// get previous style from the stack
@@ -774,7 +885,7 @@ Style * StyleEngine::style0 (int i) {
nonCssProperties);
// apply style
- apply (i, &attrs, &props);
+ apply (i, &attrs, &props, bw, url);
postprocessAttrs (&attrs);
@@ -783,14 +894,20 @@ Style * StyleEngine::style0 (int i) {
return stack->getRef (i)->style;
}
-Style * StyleEngine::wordStyle0 () {
- StyleAttrs attrs = *style ();
+Style * StyleEngine::wordStyle0 (BrowserWindow *bw, DilloUrl *url) {
+ StyleAttrs attrs = *style (bw, url);
attrs.resetValues ();
- if (stack->getRef (stack->size() - 1)->inheritBackgroundColor)
- attrs.backgroundColor = style ()->backgroundColor;
+ if (stack->getRef (stack->size() - 1)->inheritBackgroundColor) {
+ attrs.backgroundColor = style (bw, url)->backgroundColor;
+ attrs.backgroundImage = style (bw, url)->backgroundImage;
+ attrs.backgroundRepeat = style (bw, url)->backgroundRepeat;
+ attrs.backgroundAttachment = style (bw, url)->backgroundAttachment;
+ attrs.backgroundPositionX = style (bw, url)->backgroundPositionX;
+ attrs.backgroundPositionY = style (bw, url)->backgroundPositionY;
+ }
- attrs.valign = style ()->valign;
+ attrs.valign = style (bw, url)->valign;
stack->getRef(stack->size() - 1)->wordStyle = Style::create(&attrs);
return stack->getRef (stack->size () - 1)->wordStyle;
@@ -803,7 +920,7 @@ Style * StyleEngine::wordStyle0 () {
* and thereby after the HTML-element has been opened.
* Note that restyle() does not change any styles in the widget tree.
*/
-void StyleEngine::restyle () {
+void StyleEngine::restyle (BrowserWindow *bw, DilloUrl *url) {
for (int i = 1; i < stack->size (); i++) {
Node *n = stack->getRef (i);
if (n->style) {
@@ -819,7 +936,7 @@ void StyleEngine::restyle () {
n->backgroundStyle = NULL;
}
- style0 (i);
+ style0 (i, bw, url);
}
}
diff --git a/src/styleengine.hh b/src/styleengine.hh
index 237008a6..714553ff 100644
--- a/src/styleengine.hh
+++ b/src/styleengine.hh
@@ -40,8 +40,8 @@ class StyleEngine {
void stackPop ();
void buildUserAgentStyle ();
void buildUserStyle ();
- dw::core::style::Style *style0 (int i);
- dw::core::style::Style *wordStyle0 ();
+ dw::core::style::Style *style0 (int i, BrowserWindow *bw, DilloUrl *url);
+ dw::core::style::Style *wordStyle0 (BrowserWindow *bw, DilloUrl *url);
inline void setNonCssHint(CssPropertyName name, CssValueType type,
CssPropertyValue value) {
Node *n = stack->getRef (stack->size () - 1);
@@ -52,7 +52,8 @@ class StyleEngine {
}
void preprocessAttrs (dw::core::style::StyleAttrs *attrs);
void postprocessAttrs (dw::core::style::StyleAttrs *attrs);
- void apply (int i, dw::core::style::StyleAttrs *attrs, CssPropertyList *props);
+ void apply (int i, dw::core::style::StyleAttrs *attrs,
+ CssPropertyList *props, BrowserWindow *bw, DilloUrl *url);
bool computeValue (int *dest, CssLength value,
dw::core::style::Font *font);
bool computeValue (int *dest, CssLength value,
@@ -68,8 +69,8 @@ class StyleEngine {
void parse (DilloHtml *html, DilloUrl *url, const char *buf, int buflen,
CssOrigin origin);
- void startElement (int tag);
- void startElement (const char *tagname);
+ void startElement (int tag, BrowserWindow *bw, DilloUrl *url);
+ void startElement (const char *tagname, BrowserWindow *bw, DilloUrl *url);
void setId (const char *id);
const char * getId () { return doctree->top ()->id; };
void setClass (const char *klass);
@@ -91,25 +92,32 @@ class StyleEngine {
}
void inheritNonCssHints ();
void clearNonCssHints ();
- void restyle ();
+ void restyle (BrowserWindow *bw, DilloUrl *url);
void inheritBackgroundColor (); /* \todo get rid of this somehow */
- dw::core::style::Style *backgroundStyle ();
+ dw::core::style::Style *backgroundStyle (BrowserWindow *bw,
+ DilloUrl *url);
dw::core::style::Color *backgroundColor ();
+ dw::core::style::StyleImage *backgroundImage
+ (dw::core::style::BackgroundRepeat *bgRepeat,
+ dw::core::style::BackgroundAttachment *bgAttachment,
+ dw::core::style::Length *bgPositionX,
+ dw::core::style::Length *bgPositionY);
- inline dw::core::style::Style *style () {
+ inline dw::core::style::Style *style (BrowserWindow *bw, DilloUrl *url) {
dw::core::style::Style *s = stack->getRef (stack->size () - 1)->style;
if (s)
return s;
else
- return style0 (stack->size () - 1);
+ return style0 (stack->size () - 1, bw, url);
};
- inline dw::core::style::Style *wordStyle () {
+ inline dw::core::style::Style *wordStyle (BrowserWindow *bw,
+ DilloUrl *url) {
dw::core::style::Style *s = stack->getRef(stack->size()-1)->wordStyle;
if (s)
return s;
else
- return wordStyle0 ();
+ return wordStyle0 (bw, url);
};
};
diff --git a/src/table.cc b/src/table.cc
index 15200516..a3002ebf 100644
--- a/src/table.cc
+++ b/src/table.cc
@@ -114,7 +114,7 @@ void Html_tag_open_table(DilloHtml *html, const char *tag, int tagsize)
BUG_MSG("<table> bgcolor attribute is obsolete.\n");
}
- html->styleEngine->style (); // evaluate now, so we can build non-css hints for the cells
+ html->style (); // evaluate now, so we can build non-css hints for the cells
/* The style for the cells */
html->styleEngine->clearNonCssHints ();
@@ -155,10 +155,10 @@ void Html_tag_content_table(DilloHtml *html, const char *tag, int tagsize)
{
dw::core::Widget *table;
- HT2TB(html)->addParbreak (0, html->styleEngine->wordStyle ());
+ HT2TB(html)->addParbreak (0, html->wordStyle ());
table = new dw::Table(prefs.limit_text_width);
- HT2TB(html)->addWidget (table, html->styleEngine->style ());
- HT2TB(html)->addParbreak (0, html->styleEngine->wordStyle ());
+ HT2TB(html)->addWidget (table, html->style ());
+ HT2TB(html)->addParbreak (0, html->wordStyle ());
S_TOP(html)->table_mode = DILLO_HTML_TABLE_MODE_TOP;
S_TOP(html)->table_border_mode = DILLO_HTML_TABLE_BORDER_SEPARATE;
@@ -221,7 +221,7 @@ void Html_tag_content_tr(DilloHtml *html, const char *tag, int tagsize)
case DILLO_HTML_TABLE_MODE_TOP:
case DILLO_HTML_TABLE_MODE_TR:
case DILLO_HTML_TABLE_MODE_TD:
- ((dw::Table*)S_TOP(html)->table)->addRow (html->styleEngine->style ());
+ ((dw::Table*)S_TOP(html)->table)->addRow (html->style ());
default:
break;
}
@@ -302,10 +302,10 @@ static void Html_set_collapsing_border_model(DilloHtml *html, Widget *col_tb)
int borderWidth, marginWidth;
tableStyle = ((dw::Table*)S_TOP(html)->table)->getStyle ();
- borderWidth = html->styleEngine->style ()->borderWidth.top;
+ borderWidth = html->style ()->borderWidth.top;
marginWidth = tableStyle->margin.top;
- collapseCellAttrs = *(html->styleEngine->style ());
+ collapseCellAttrs = *(html->style ());
collapseCellAttrs.margin.setVal (0);
collapseCellAttrs.borderWidth.left = 0;
collapseCellAttrs.borderWidth.top = 0;
@@ -344,7 +344,7 @@ static void Html_set_separate_border_model(DilloHtml *html, Widget *col_tb)
dw::core::style::Style *separateStyle;
dw::core::style::StyleAttrs separateCellAttrs;
- separateCellAttrs = *(html->styleEngine->style ());
+ separateCellAttrs = *(html->style ());
/* CSS2 17.5: Internal table elements do not have margins */
separateCellAttrs.margin.setVal (0);
separateStyle = Style::create(&separateCellAttrs);
@@ -443,7 +443,7 @@ static void Html_tag_content_table_cell(DilloHtml *html,
/* TODO: check errors? */
if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "rowspan")))
rowspan = MAX(1, strtol (attrbuf, NULL, 10));
- if (html->styleEngine->style ()->textAlign
+ if (html->style ()->textAlign
== TEXT_ALIGN_STRING)
col_tb = new dw::TableCell (
((dw::Table*)S_TOP(html)->table)->getCellRef (),
@@ -451,7 +451,7 @@ static void Html_tag_content_table_cell(DilloHtml *html,
else
col_tb = new Textblock (prefs.limit_text_width);
- if (html->styleEngine->style()->borderCollapse == BORDER_MODEL_COLLAPSE){
+ if (html->style()->borderCollapse == BORDER_MODEL_COLLAPSE){
Html_set_collapsing_border_model(html, col_tb);
} else {
Html_set_separate_border_model(html, col_tb);
diff --git a/src/uicmd.cc b/src/uicmd.cc
index 84e7e4cd..4f737255 100644
--- a/src/uicmd.cc
+++ b/src/uicmd.cc
@@ -583,6 +583,9 @@ static BrowserWindow *UIcmd_tab_new(CustTabs *tabs, UI *old_ui, int focus)
Layout *layout = new Layout (platform);
style::Color *bgColor = style::Color::create (layout, prefs.bg_color);
layout->setBgColor (bgColor);
+ layout->setBgImage (NULL, style::BACKGROUND_REPEAT,
+ style::BACKGROUND_ATTACHMENT_SCROLL,
+ style::createPerLength (0), style::createPerLength (0));
// set_render_layout() sets the proper viewport size
FltkViewport *viewport = new FltkViewport (0, 0, 0, 1);
diff --git a/src/web.cc b/src/web.cc
index fcc65af8..0a8ee710 100644
--- a/src/web.cc
+++ b/src/web.cc
@@ -67,16 +67,20 @@ int a_Web_dispatch_by_type (const char *Type, DilloWeb *Web,
style::Color *bgColor = style::Color::create (layout, prefs.bg_color);
Web->bgColor = bgColor->getColor ();
layout->setBgColor (bgColor);
+ layout->setBgImage (NULL, style::BACKGROUND_REPEAT,
+ style::BACKGROUND_ATTACHMENT_SCROLL,
+ style::createPerLength (0),
+ style::createPerLength (0));
/* Set a style for the widget */
StyleEngine styleEngine (layout);
- styleEngine.startElement ("body");
+ styleEngine.startElement ("body", Web->bw, Web->url);
dw = (Widget*) viewer(Type, Web, Call, Data);
if (dw == NULL)
return -1;
- dw->setStyle (styleEngine.style ());
+ dw->setStyle (styleEngine.style (Web->bw, Web->url));
/* This method frees the old dw if any */
layout->setWidget(dw);
diff --git a/test/Makefile.am b/test/Makefile.am
index db7b65b9..35689ec3 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -10,6 +10,7 @@ noinst_PROGRAMS = \
dw-float-test \
dw-links \
dw-links2 \
+ dw-image-background \
dw-images-simple \
dw-images-scaled \
dw-images-scaled2 \
@@ -76,6 +77,14 @@ dw_links2_LDADD = \
$(top_builddir)/lout/liblout.a \
@LIBFLTK_LIBS@
+dw_image_background_SOURCES = dw_image_background.cc
+dw_image_background_LDADD = \
+ $(top_builddir)/dw/libDw-widgets.a \
+ $(top_builddir)/dw/libDw-fltk.a \
+ $(top_builddir)/dw/libDw-core.a \
+ $(top_builddir)/lout/liblout.a \
+ @LIBFLTK_LIBS@
+
dw_images_simple_SOURCES = dw_images_simple.cc
dw_images_simple_LDADD = \
$(top_builddir)/dw/libDw-widgets.a \
diff --git a/test/dw_image_background.cc b/test/dw_image_background.cc
new file mode 100644
index 00000000..24966850
--- /dev/null
+++ b/test/dw_image_background.cc
@@ -0,0 +1,196 @@
+/*
+ * Dillo Widget
+ *
+ * Copyright 2013 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+
+#include "../dw/core.hh"
+#include "../dw/fltkcore.hh"
+#include "../dw/fltkviewport.hh"
+#include "../dw/textblock.hh"
+#include "../dw/image.hh"
+
+using namespace lout::signal;
+using namespace lout::misc;
+using namespace dw;
+using namespace dw::core;
+using namespace dw::core::style;
+using namespace dw::fltk;
+
+class ImageStyleDeletionReceiver: public ObservedObject::DeletionReceiver
+{
+public:
+ void deleted (ObservedObject *object);
+};
+
+static StyleImage *image1 = NULL, *image2 = NULL;
+static Layout *layout;
+static int imgRow1 = 0, imgRow2 = 0;
+static ImageStyleDeletionReceiver isdr;
+
+void ImageStyleDeletionReceiver::deleted (ObservedObject *object)
+{
+ if ((StyleImage*)object == image1)
+ image1 = NULL;
+ else if ((StyleImage*)object == image2)
+ image2 = NULL;
+ else
+ assertNotReached ();
+}
+
+static void imageInitTimeout (void *data)
+{
+ if (image1) {
+ Imgbuf *imgbuf1 = layout->createImgbuf (Imgbuf::RGB, 400, 200, 1);
+ image1->getMainImgRenderer()->setBuffer (imgbuf1, false);
+ }
+
+ if (image2) {
+ Imgbuf *imgbuf2 = layout->createImgbuf (Imgbuf::RGB, 100, 100, 1);
+ image2->getMainImgRenderer()->setBuffer (imgbuf2, false);
+ }
+}
+
+static void imageDrawTimeout (void *data)
+{
+ Imgbuf *imgbuf1 = image1 ? image1->getImgbufSrc () : NULL;
+ Imgbuf *imgbuf2 = image2 ? image2->getImgbufSrc () : NULL;
+
+ if (imgbuf1 && imgRow1 < 200) {
+ byte buf[3 * 400];
+ for(int x = 0; x < 400; x++) {
+ buf[3 * x + 0] = 128 + x * 127 / 399;
+ buf[3 * x + 1] = 128 + (399 - x) * 127 / 399;
+ buf[3 * x + 2] = 128 + imgRow1 * 127 / 199;
+ }
+
+ imgbuf1->copyRow (imgRow1, buf);
+ image1->getMainImgRenderer()->drawRow (imgRow1);
+ imgRow1++;
+ }
+
+ if (imgbuf2 && imgRow2 < 100) {
+ byte buf[3 * 100];
+ for(int x = 0; x < 100; x++) {
+ int r = 128 + rand () % 127;
+ buf[3 * x + 0] = buf[3 * x + 1] = buf[3 * x + 2] = r;
+ }
+
+ imgbuf2->copyRow (imgRow2, buf);
+ image2->getMainImgRenderer()->drawRow (imgRow2);
+ imgRow2++;
+ }
+
+ if(imgRow1 < 200 || imgRow2 < 100)
+ Fl::repeat_timeout (0.5, imageDrawTimeout, NULL);
+}
+
+int main(int argc, char **argv)
+{
+ FltkPlatform *platform = new FltkPlatform ();
+ layout = new Layout (platform);
+
+ Fl_Window *window = new Fl_Window(200, 300, "Dw Example");
+ window->box(FL_NO_BOX);
+ window->begin();
+
+ FltkViewport *viewport = new FltkViewport (0, 0, 200, 300);
+ layout->attachView (viewport);
+
+ image1 = StyleImage::create ();
+ image1->connectDeletion (&isdr);
+ layout->setBgImage (image1, BACKGROUND_REPEAT_Y,
+ BACKGROUND_ATTACHMENT_SCROLL, createPerLength (0.5),
+ createAbsLength (30));
+
+ StyleAttrs styleAttrs;
+ styleAttrs.initValues ();
+ styleAttrs.margin.setVal (5);
+ styleAttrs.x_lang[0] = 'e';
+ styleAttrs.x_lang[1] = 'n';
+
+ FontAttrs fontAttrs;
+ fontAttrs.name = "Bitstream Charter";
+ fontAttrs.size = 14;
+ fontAttrs.weight = 400;
+ fontAttrs.style = FONT_STYLE_NORMAL;
+ fontAttrs.letterSpacing = 0;
+ fontAttrs.fontVariant = FONT_VARIANT_NORMAL;
+ styleAttrs.font = style::Font::create (layout, &fontAttrs);
+
+ styleAttrs.color = Color::create (layout, 0x000000);
+ //styleAttrs.backgroundColor = Color::create (layout, 0xffffff);
+
+ Style *widgetStyle = Style::create (&styleAttrs);
+
+ Textblock *textblock = new Textblock (false);
+ textblock->setStyle (widgetStyle);
+ layout->setWidget (textblock);
+
+ widgetStyle->unref();
+
+ styleAttrs.margin.setVal (0);
+ styleAttrs.backgroundColor = NULL;
+ styleAttrs.backgroundImage = NULL;
+
+ Style *wordStyle = Style::create (&styleAttrs);
+
+ image2 = styleAttrs.backgroundImage = StyleImage::create ();
+ image2->connectDeletion (&isdr);
+ styleAttrs.backgroundRepeat = BACKGROUND_REPEAT;
+ styleAttrs.backgroundPositionX = createPerLength (0);
+ styleAttrs.backgroundPositionY = createPerLength (0);
+ Style *wordStyleBg = Style::create (&styleAttrs);
+
+ for(int i = 1; i <= 1; i++) {
+ char buf[4];
+ sprintf(buf, "%d.", i);
+
+ const char *words[] = { "This", "is", "the", buf, "paragraph.",
+ "Here", "comes", "some", "more", "text",
+ "to", "demonstrate", "word", "wrapping.",
+ NULL };
+
+ for(int j = 0; words[j]; j++) {
+ textblock->addText(words[j], j == 11 ? wordStyleBg : wordStyle);
+ textblock->addSpace(wordStyle);
+ }
+
+ textblock->addParbreak(10, wordStyle);
+ }
+
+ wordStyle->unref();
+ wordStyleBg->unref();
+
+ textblock->flush ();
+
+ window->resizable(viewport);
+ window->show();
+
+ Fl::add_timeout (1.0, imageInitTimeout, NULL);
+ Fl::add_timeout (0.1, imageDrawTimeout, NULL);
+
+ int errorCode = Fl::run();
+
+ delete layout;
+
+ return errorCode;
+}