aboutsummaryrefslogtreecommitdiff
path: root/dw/textblock.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dw/textblock.cc')
-rw-r--r--dw/textblock.cc455
1 files changed, 379 insertions, 76 deletions
diff --git a/dw/textblock.cc b/dw/textblock.cc
index 068a7c0d..fc298562 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -24,13 +24,14 @@
#include "../lout/unicode.hh"
#include <stdio.h>
-#include <math.h>
+#include <math.h> // remove again?
+#include <limits.h>
/*
* Local variables
*/
- /* The tooltip under mouse pointer in current textblock. No ref. hold.
- * (having one per view looks not worth the extra clutter). */
+/* The tooltip under mouse pointer in current textblock. No ref. hold.
+ * (having one per view looks not worth the extra clutter). */
static dw::core::style::Tooltip *hoverTooltip = NULL;
@@ -144,6 +145,7 @@ Textblock::Textblock (bool limitTextWidth)
nonTemporaryLines = 0;
words = new misc::NotSoSimpleVector <Word> (1);
anchors = new misc::SimpleVector <Anchor> (1);
+ outOfFlowMgr = NULL;
//DBG_OBJ_SET_NUM(this, "num_lines", num_lines);
@@ -161,6 +163,9 @@ Textblock::Textblock (bool limitTextWidth)
availAscent = 100;
availDescent = 0;
+ diffXToContainingBlock = restWidthToContainingBlock =
+ diffYToContainingBlock = -1;
+
this->limitTextWidth = limitTextWidth;
for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
@@ -181,8 +186,9 @@ Textblock::~Textblock ()
for (int i = 0; i < words->size(); i++) {
Word *word = words->getRef (i);
- if (word->content.type == core::Content::WIDGET)
+ if (word->content.type == core::Content::WIDGET_IN_FLOW)
delete word->content.widget;
+ /** \todo Widget references? What about texts? */
word->style->unref ();
word->spaceStyle->unref ();
}
@@ -198,6 +204,9 @@ Textblock::~Textblock ()
delete words;
delete anchors;
+ if(outOfFlowMgr)
+ delete outOfFlowMgr;
+
/* Make sure we don't own widgets anymore. Necessary before call of
parent class destructor. (???) */
words = NULL;
@@ -252,6 +261,21 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
requisition->ascent += getStyle()->boxOffsetY ();
requisition->descent += getStyle()->boxRestHeight ();
+ // Dealing with parts out of flow, which may overlap the borders of
+ // the text block. Base lines are ignored here: they do not play a
+ // role (currently) and caring about them (for the future) would
+ // cause too much problems.
+
+ if (outOfFlowMgr) {
+ int oofWidth, oofHeight;
+ outOfFlowMgr->getSize (requisition->width,
+ requisition->ascent + requisition->descent,
+ &oofWidth, &oofHeight);
+ requisition->width = misc::max (requisition->width, oofWidth);
+ if (oofHeight > requisition->ascent + requisition->descent)
+ requisition->descent = oofHeight - requisition->ascent;
+ }
+
if (requisition->width < availWidth)
requisition->width = availWidth;
@@ -264,7 +288,7 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
*/
void Textblock::getWordExtremes (Word *word, core::Extremes *extremes)
{
- if (word->content.type == core::Content::WIDGET) {
+ if (word->content.type == core::Content::WIDGET_IN_FLOW) {
if (word->content.widget->usesHints ())
word->content.widget->getExtremes (extremes);
else {
@@ -338,7 +362,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
for (lineIndex = 0; lineIndex < lines->size (); lineIndex++) {
line = lines->getRef (lineIndex);
- xCursor = lineXOffsetWidget (line);
+ xCursor = line->offsetCompleteWidget;
for (wordIndex = line->firstWord; wordIndex <= line->lastWord;
wordIndex++) {
@@ -348,7 +372,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
redrawY = misc::min (redrawY, lineYOffsetWidget (line));
}
- if (word->content.type == core::Content::WIDGET) {
+ if (word->content.type == core::Content::WIDGET_IN_FLOW) {
/** \todo Justification within the line is done here. */
childAllocation.x = xCursor + allocation->x;
/* align=top:
@@ -420,6 +444,9 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
}
}
+ if(outOfFlowMgr)
+ outOfFlowMgr->sizeAllocate(allocation);
+
for (int i = 0; i < anchors->size(); i++) {
Anchor *anchor = anchors->getRef(i);
int y;
@@ -450,47 +477,118 @@ void Textblock::resizeDrawImpl ()
void Textblock::markSizeChange (int ref)
{
+ if (OutOfFlowMgr::isRefOutOfFlow (ref)) {
+ assert (outOfFlowMgr != NULL);
+ outOfFlowMgr->markSizeChange (ref);
+ } else {
+ PRINTF ("[%p] MARK_SIZE_CHANGE (%d): %d => ...\n",
+ this, ref, wrapRefLines);
+
+ /* By the way: ref == -1 may have two different causes: (i) flush()
+ calls "queueResize (-1, true)", when no rewrapping is necessary;
+ and (ii) a word may have parentRef == -1 , when it is not yet
+ added to a line. In the latter case, nothing has to be done
+ now, but addLine(...) will do everything necessary. */
+ if (ref != -1) {
+ if (wrapRefLines == -1)
+ wrapRefLines = OutOfFlowMgr::getLineNoFromRef (ref);
+ else
+ wrapRefLines = misc::min (wrapRefLines,
+ OutOfFlowMgr::getLineNoFromRef (ref));
+ }
+
+ PRINTF (" ... => %d\n", wrapRefLine);
+
+ // It seems that sometimes (even without floats) the lines
+ // structure is changed, so that wrapRefLines may refers to a
+ // line which does not exist anymore. Should be examined
+ // again. Until then, setting wrapRefLines to the same value is
+ // a workaround.
+ markExtremesChange (ref);
+ }
+}
+
+void Textblock::markExtremesChange (int ref)
+{
PRINTF ("[%p] MARK_SIZE_CHANGE (%d): %d => ...\n", this, ref, wrapRefLines);
- /* By the way: ref == -1 may have two different causes: (i) flush()
- calls "queueResize (-1, true)", when no rewrapping is necessary;
- and (ii) a word may have parentRef == -1 , when it is not yet
- added to a line. In the latter case, nothing has to be done
- now, but addLine(...) will do everything necessary. */
- if (ref != -1) {
- if (wrapRefLines == -1)
- wrapRefLines = ref;
- else
- wrapRefLines = misc::min (wrapRefLines, ref);
+ if (OutOfFlowMgr::isRefOutOfFlow (ref)) {
+ assert (outOfFlowMgr != NULL);
+ outOfFlowMgr->markExtremesChange (ref);
+ } else {
+ PRINTF ("[%p] MARK_EXTREMES_CHANGE (%d): %d => ...\n",
+ this, ref, wrapRefParagraphs);
+
+ /* By the way: ref == -1 may have two different causes: (i) flush()
+ calls "queueResize (-1, true)", when no rewrapping is necessary;
+ and (ii) a word may have parentRef == -1 , when it is not yet
+ added to a line. In the latter case, nothing has to be done
+ now, but addLine(...) will do everything necessary. */
+ if (ref != -1) {
+ if (wrapRefParagraphs == -1)
+ wrapRefParagraphs = OutOfFlowMgr::getLineNoFromRef (ref);
+ else
+ wrapRefParagraphs =
+ misc::min (wrapRefParagraphs,
+ OutOfFlowMgr::getLineNoFromRef (ref));
+ }
+
+ PRINTF (" ... => %d\n", wrapRefParagraphs);
}
+}
- PRINTF (" ... => %d\n", wrapRefLine);
+void Textblock::notifySetAsTopLevel()
+{
+ PRINTF ("%p becomes toplevel\n", this);
+ containingBlock = this;
+ diffXToContainingBlock = restWidthToContainingBlock =
+ diffYToContainingBlock = 0;
+ PRINTF ("-> %p is its own containing block\n", this);
+}
- // It seems that sometimes the lines structure is changed, so that
- // wrapRefLines may refers to a line which does not exist
- // anymore. Should be examined again. Until then, setting
- // wrapRefLines to the same value is a workaround.
- markExtremesChange (ref);
+bool Textblock::isContainingBlock (Widget *widget)
+{
+ return
+ // Of course, only textblocks are considered as containing
+ // blocks.
+ widget->instanceOf (Textblock::CLASS_ID) &&
+ // The second condition: that this block is "out of flow", in a
+ // wider sense.
+ (// The toplevel widget is "out of flow", since there is no
+ // parent, and so no context.
+ widget->getParent() == NULL ||
+ // A similar reasoning applies to a widget with another parent
+ // than a textblock (typical example: a table cell (this is
+ // also a text block) within a table widget).
+ !widget->getParent()->instanceOf (Textblock::CLASS_ID) ||
+ // Finally, "out of flow" in a narrower sense: floats and
+ // absolute positions.
+ OutOfFlowMgr::isWidgetOutOfFlow (widget));
}
-void Textblock::markExtremesChange (int ref)
+void Textblock::notifySetParent ()
{
- PRINTF ("[%p] MARK_EXTREMES_CHANGE (%d): %d => ...\n",
- this, ref, wrapRefParagraphs);
-
- /* By the way: ref == -1 may have two different causes: (i) flush()
- calls "queueResize (-1, true)", when no rewrapping is necessary;
- and (ii) a word may have parentRef == -1 , when it is not yet
- added to a line. In the latter case, nothing has to be done
- now, but addLine(...) will do everything necessary. */
- if (ref != -1) {
- if (wrapRefParagraphs == -1)
- wrapRefParagraphs = ref;
- else
- wrapRefParagraphs = misc::min (wrapRefParagraphs, ref);
- }
+ PRINTF ("%p becomes a child of %p\n", this, getParent());
+
+ // Search for containing Box.
+ containingBlock = NULL;
- PRINTF (" ... => %d\n", wrapRefParagraphs);
+ for (Widget *widget = this; widget != NULL && containingBlock == NULL;
+ widget = widget->getParent())
+ if (isContainingBlock (widget)) {
+ containingBlock = (Textblock*)widget;
+
+ if (containingBlock == this) {
+ diffXToContainingBlock = restWidthToContainingBlock =
+ diffYToContainingBlock = 0;
+ PRINTF ("-> %p is its own containing block\n", this);
+ } else {
+ PRINTF ("-> %p becomes containing block of %p\n",
+ containingBlock, this);
+ }
+ }
+
+ assert (containingBlock != NULL);
}
void Textblock::setWidth (int width)
@@ -504,10 +602,13 @@ void Textblock::setWidth (int width)
// words->size());
availWidth = width;
- queueResize (0, false);
+ queueResize (OutOfFlowMgr::createRefNormalFlow (0), false);
mustQueueResize = false;
redrawY = 0;
}
+
+ if (outOfFlowMgr)
+ outOfFlowMgr->setWidth (width);
}
void Textblock::setAscent (int ascent)
@@ -519,9 +620,12 @@ void Textblock::setAscent (int ascent)
// words->size());
availAscent = ascent;
- queueResize (0, false);
+ queueResize (OutOfFlowMgr::createRefNormalFlow (0), false);
mustQueueResize = false;
}
+
+ if (outOfFlowMgr)
+ outOfFlowMgr->setAscent (ascent);
}
void Textblock::setDescent (int descent)
@@ -533,9 +637,12 @@ void Textblock::setDescent (int descent)
// words->size());
availDescent = descent;
- queueResize (0, false);
+ queueResize (OutOfFlowMgr::createRefNormalFlow (0), false);
mustQueueResize = false;
}
+
+ if (outOfFlowMgr)
+ outOfFlowMgr->setDescent (descent);
}
bool Textblock::buttonPressImpl (core::EventButton *event)
@@ -650,11 +757,11 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType,
// Choose this break.
wordIndex = line->lastWord;
charPos = core::SelectionState::END_OF_WORD;
- } else if (event->xWidget < lineXOffsetWidget (line)) {
+ } else if (event->xWidget < line->offsetCompleteWidget) {
// Left of the first word in the line.
wordIndex = line->firstWord;
} else {
- int nextWordStartX = lineXOffsetWidget (line);
+ int nextWordStartX = line->offsetCompleteWidget;
for (wordIndex = line->firstWord;
wordIndex <= line->lastWord;
@@ -734,8 +841,9 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType,
}
}
}
- it = new TextblockIterator (this, core::Content::SELECTION_CONTENT,
- wordIndex);
+
+ it = new TextblockIterator (this, core::Content::maskForSelection (true),
+ false, wordIndex);
r = selectionHandleEvent (eventType, it, charPos, link, event);
it->unref ();
return r;
@@ -767,6 +875,32 @@ void Textblock::calcWidgetSize (core::Widget *widget, core::Requisition *size)
availAscent = this->availAscent - getStyle()->boxDiffHeight ();
availDescent = this->availDescent;
+ // The following should be changed, made more general, and so on.
+ //
+ // With floats, the implementation of Textblock::sizeRequestImpl
+ // becomes special: Textblock::sizeRequestImpl will rewrap lines,
+ // for which the line widths are needed, which depend on floats;
+ // however, if a text block is not its containing block, the floats
+ // positions depend on the position text block within the text
+ // container.
+ //
+ // This is something new, and should be implemented in a more
+ // general way, perhaps resembling size hints.
+
+ // Tell a child textblock its position within the containing block.
+
+ if (widget->instanceOf (Textblock::CLASS_ID)) {
+ Textblock *tb = (Textblock*)widget;
+ if (tb != tb->containingBlock) {
+ tb->diffXToContainingBlock =
+ diffXToContainingBlock + getStyle()->boxOffsetX();
+ tb->restWidthToContainingBlock =
+ restWidthToContainingBlock + getStyle()->boxRestWidth();;
+ tb->diffYToContainingBlock =
+ diffYToContainingBlock + topOfPossiblyMissingLine (lines->size ());
+ }
+ }
+
if (widget->usesHints ()) {
widget->setWidth (availWidth);
widget->setAscent (availAscent);
@@ -1101,7 +1235,7 @@ void Textblock::drawSpace(int wordIndex, core::View *view,
*/
void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
{
- int xWidget = lineXOffsetWidget(line);
+ int xWidget = line->offsetCompleteWidget;
int yWidgetBase = lineYOffsetWidget (line) + line->boxAscent;
for (int wordIndex = line->firstWord;
@@ -1112,10 +1246,10 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
if (xWidget + wordSize + word->hyphenWidth + word->effSpace >= area->x) {
if (word->content.type == core::Content::TEXT ||
- word->content.type == core::Content::WIDGET) {
+ word->content.type == core::Content::WIDGET_IN_FLOW) {
if (word->size.width > 0) {
- if (word->content.type == core::Content::WIDGET) {
+ if (word->content.type == core::Content::WIDGET_IN_FLOW) {
core::Widget *child = word->content.widget;
core::Rectangle childArea;
@@ -1259,7 +1393,7 @@ Textblock::Word *Textblock::findWord (int x, int y, bool *inSpace)
if (yWidgetBase + line->boxDescent <= y)
return NULL;
- xCursor = lineXOffsetWidget (line);
+ xCursor = line->offsetCompleteWidget;
for (wordIndex = line->firstWord; wordIndex <= line->lastWord;wordIndex++) {
word = words->getRef (wordIndex);
lastXCursor = xCursor;
@@ -1305,6 +1439,9 @@ void Textblock::draw (core::View *view, core::Rectangle *area)
drawLine (line, view, area);
}
+
+ if(outOfFlowMgr)
+ outOfFlowMgr->draw(view, area);
}
/**
@@ -1704,28 +1841,48 @@ void Textblock::addText0 (const char *text, size_t len, short flags,
*/
void Textblock::addWidget (core::Widget *widget, core::style::Style *style)
{
- Word *word;
- core::Requisition size;
-
/* We first assign -1 as parent_ref, since the call of widget->size_request
* will otherwise let this Textblock be rewrapped from the beginning.
* (parent_ref is actually undefined, but likely has the value 0.) At the,
* end of this function, the correct value is assigned. */
widget->parentRef = -1;
- PRINTF ("%p becomes child of %p\n", widget, this);
-
- widget->setParent (this);
widget->setStyle (style);
- calcWidgetSize (widget, &size);
- word = addWord (size.width, size.ascent, size.descent, 0, style);
+ PRINTF ("adding the %s %p to %p ...\n",
+ widget->getClassName(), widget, this);
+
+ if (OutOfFlowMgr::isWidgetOutOfFlow (widget)) {
+ PRINTF (" -> out of flow.\n");
+
+ if (containingBlock->outOfFlowMgr == NULL) {
+ containingBlock->outOfFlowMgr = new OutOfFlowMgr (containingBlock);
+ containingBlock->outOfFlowMgr->setWidth (containingBlock->availWidth);
+ containingBlock->outOfFlowMgr->setAscent
+ (containingBlock->availAscent);
+ containingBlock->outOfFlowMgr->setDescent
+ (containingBlock->availDescent);
+ }
+
+ widget->setParent (containingBlock);
+ widget->setGenerator (this);
+ containingBlock->outOfFlowMgr->addWidget (widget, this);
+ Word *word = addWord (0, 0, 0, false, style);
+ word->content.type = core::Content::WIDGET_OOF_REF;
+ word->content.widget = widget;
+ word->style = style;
+ } else {
+ PRINTF (" -> within flow.\n");
- word->content.type = core::Content::WIDGET;
- word->content.widget = widget;
+ widget->setParent (this);
- //DBG_OBJ_ARRSET_PTR (page, "words.%d.content.widget", words->size() - 1,
- // word->content.widget);
+ core::Requisition size;
+ calcWidgetSize (widget, &size);
+ Word *word =
+ addWord (size.width, size.ascent, size.descent, 0, style);
+ word->content.type = core::Content::WIDGET_IN_FLOW;
+ word->content.widget = widget;
+ }
processWord (words->size () - 1);
//DBG_OBJ_SET_NUM (word->content.widget, "parent_ref",
@@ -1865,7 +2022,7 @@ void Textblock::addParbreak (int space, core::style::Style *style)
/* A break may not be the first word of a page, or directly after
the bullet/number (which is the first word) in a list item. (See
- also comment in Dw_page_size_request.) */
+ also comment in sizeRequest.) */
if (words->size () == 0 ||
(hasListitemValue && words->size () == 1)) {
/* This is a bit hackish: If a break is added as the
@@ -1874,23 +2031,23 @@ void Textblock::addParbreak (int space, core::style::Style *style)
a widget is used as a text box (lists, blockquotes, list
items etc) -- then we simply adjust the break before, in a
way that the space is in any case visible. */
- Widget *widget;
-
- /* Find the widget where to adjust the breakSpace. */
- for (widget = this;
- widget->getParent() &&
- widget->getParent()->instanceOf (Textblock::CLASS_ID);
+ /* Find the widget where to adjust the breakSpace. (Only
+ consider normal flow, no floats etc.) */
+ for (Widget *widget = this;
+ widget->getParent() != NULL &&
+ widget->getParent()->instanceOf (Textblock::CLASS_ID) &&
+ !OutOfFlowMgr::isRefOutOfFlow (widget->parentRef);
widget = widget->getParent ()) {
Textblock *textblock2 = (Textblock*)widget->getParent ();
int index = textblock2->hasListitemValue ? 1 : 0;
bool isfirst = (textblock2->words->getRef(index)->content.type
- == core::Content::WIDGET
+ == core::Content::WIDGET_IN_FLOW
&& textblock2->words->getRef(index)->content.widget
== widget);
if (!isfirst) {
- /* The page we searched for has been found. */
+ /* The text block we searched for has been found. */
Word *word2;
- int lineno = widget->parentRef;
+ int lineno = OutOfFlowMgr::getLineNoFromRef (widget->parentRef);
if (lineno > 0 &&
(word2 =
@@ -1899,7 +2056,8 @@ void Textblock::addParbreak (int space, core::style::Style *style)
word2->content.type == core::Content::BREAK) {
if (word2->content.breakSpace < space) {
word2->content.breakSpace = space;
- textblock2->queueResize (lineno, false);
+ textblock2->queueResize
+ (OutOfFlowMgr::createRefNormalFlow (lineno), false);
textblock2->mustQueueResize = false;
}
}
@@ -1907,6 +2065,7 @@ void Textblock::addParbreak (int space, core::style::Style *style)
}
/* Otherwise continue to examine parents. */
}
+
/* Return in any case. */
return;
}
@@ -1955,7 +2114,6 @@ void Textblock::addLinebreak (core::style::Style *style)
processWord (words->size () - 1);
}
-
/**
* \brief Search recursively through widget.
*
@@ -1964,6 +2122,10 @@ void Textblock::addLinebreak (core::style::Style *style)
*/
core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level)
{
+ //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n",
+ // 3 * level, "", getClassName (), this, allocation.x, allocation.y,
+ // allocation.width, allocation.ascent, allocation.descent);
+
int lineIndex, wordIndex;
Line *line;
@@ -1974,6 +2136,14 @@ core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level)
return NULL;
}
+ // First, search for widgets out of flow, notably floats, since
+ // there are cases where they overlap child textblocks. Should
+ // later be refined using z-index.
+ Widget *oofWidget =
+ outOfFlowMgr ? outOfFlowMgr->getWidgetAtPoint (x, y, level) : NULL;
+ if (oofWidget)
+ return oofWidget;
+
lineIndex = findLineIndex (y - allocation.y);
if (lineIndex < 0 || lineIndex >= lines->size ()) {
@@ -1985,7 +2155,7 @@ core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level)
for (wordIndex = line->firstWord; wordIndex <= line->lastWord;wordIndex++) {
Word *word = words->getRef (wordIndex);
- if (word->content.type == core::Content::WIDGET) {
+ if (word->content.type == core::Content::WIDGET_IN_FLOW) {
core::Widget * childAtPoint;
childAtPoint = word->content.widget->getWidgetAtPoint (x, y,
level + 1);
@@ -2066,7 +2236,7 @@ void Textblock::changeLinkColor (int link, int newColor)
old_style->unref();
break;
}
- case core::Content::WIDGET:
+ case core::Content::WIDGET_IN_FLOW:
{ core::Widget *widget = word->content.widget;
styleAttrs = *widget->getStyle();
styleAttrs.color = core::style::Color::create (layout,
@@ -2118,4 +2288,137 @@ void Textblock::queueDrawRange (int index1, int index2)
}
}
+void Textblock::borderChanged (int y)
+{
+ PRINTF ("[%p] Border has changed: %d\n", this, y);
+ borderChanged (y, true);
+ PRINTF ("[%p] Done.\n", this);
+}
+
+void Textblock::borderChanged (int yWidget, bool extremesChanges)
+{
+ PRINTF ("[%p] Border has changed: %d (extremes: %s)\n",
+ this, yWidget, extremesChanges ? "true" : "false");
+
+ // Notice that this method is, unlike the other "borderChanged",
+ // called (i) with canvas coordinates, not widget coordinates, and
+ // (ii) for all nested textblocks, not only the containing block.
+
+ // findLineIndex expects widget coordinates
+ int lineIndex = findLineIndex (yWidget);
+ // Nothing to do at all, when lineIndex >= lines->size (),
+ // i. e. the change is below the bottom od this widget.
+ if (lineIndex < lines->size ()) {
+ int wrapLineIndex;
+ if (lineIndex < 0)
+ // Rewrap all.
+ wrapLineIndex = 0;
+ else
+ wrapLineIndex = lineIndex;
+
+ PRINTF ("[%p] Rewrapping from line %d.\n", this, wrapLineIndex);
+ queueResize (OutOfFlowMgr::createRefNormalFlow (wrapLineIndex),
+ extremesChanges);
+
+ // lines->size () + 1 here, to get a possibly "missing" line.
+ // TODO: May there me more than one missing line? Should perhaps
+ // reworked again.
+
+ // We iterate over the lines to get the top of the line, as
+ // vertical position of the widget (provided that this is the
+ // only widget in the line). The allocation cannot be used here,
+ // since it cannot be assumed that the widget has been
+ // allocated.
+ for (int lineNo = wrapLineIndex; lineNo < lines->size () + 1; lineNo++) {
+ Textblock *childBlock = getTextblockForLine (lineNo);
+ if (childBlock)
+ // extremes only change for the containing block, so we pass
+ // extremesChanges = false for all other widgets.
+ childBlock->borderChanged (yWidget
+ - topOfPossiblyMissingLine (lineNo),
+ false);
+ }
+ }
+}
+
+Textblock *Textblock::getTextblockForLine (Line *line)
+{
+ return getTextblockForLine (line->firstWord, line->lastWord);
+}
+
+Textblock *Textblock::getTextblockForLine (int lineNo)
+{
+ int firstWord = lineNo == 0 ? 0 :lines->getRef(lineNo - 1)->lastWord + 1;
+ int lastWord = lineNo < lines->size() ?
+ lines->getRef(lineNo)->lastWord : words->size() - 1;
+ return getTextblockForLine (firstWord, lastWord);
+}
+
+Textblock *Textblock::getTextblockForLine (int firstWord, int lastWord)
+{
+ if (firstWord < words->size ()) {
+ for (int wordIndex = firstWord; wordIndex <= lastWord;
+ wordIndex++) {
+ Word *word = words->getRef (wordIndex);
+
+ if (word->content.type == core::Content::WIDGET_IN_FLOW &&
+ word->content.widget->instanceOf (Textblock::CLASS_ID)) {
+ //printf ("[%p] (line %d of %d (from %d to %d), word %d) ",
+ // this, lineNo, lines->size (), firstWord, lastWord,
+ // wordIndex);
+ //printWordShort (word);
+ //printf ("\n");
+
+ return (Textblock*)word->content.widget;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Includes margin, border, and padding.
+ */
+int Textblock::topOfPossiblyMissingLine (int lineNo)
+{
+ if (lineNo == 0)
+ return getStyle()->boxOffsetY();
+ else {
+ Line *prevLine = lines->getRef (lineNo - 1);
+ return prevLine->top + prevLine->boxAscent + prevLine->boxDescent +
+ prevLine->breakSpace + getStyle()->boxOffsetY();
+ }
+}
+
+int Textblock::heightOfPossiblyMissingLine (int lineNo)
+{
+ if (lineNo < lines->size()) {
+ // An existing line.
+ Line *line = lines->getRef (lineNo);
+ return line->boxAscent + line->boxDescent;
+ } else if (lineNo == lines->size()) {
+ // The line to be constructed: some words exist, but not the
+ // line. Accumulate the word heights. TODO Could be faster by
+ // accumulating them when words are added.
+
+ // Furthermore, this is in some cases incomplete: see
+ // doc/dw-out-of-flow.doc.
+
+ int h = 1;
+ int firstWord = lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0;
+ for (int i = firstWord; i < words->size(); i++) {
+ Word *word = words->getRef (i);
+ h = misc::max (h, word->size.ascent + word->size.descent);
+ }
+ return h;
+ } else
+ return 1;
+}
+
+core::Widget *Textblock::asWidget ()
+{
+ return this;
+}
+
} // namespace dw