aboutsummaryrefslogtreecommitdiff
path: root/dw/textblock.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dw/textblock.cc')
-rw-r--r--dw/textblock.cc842
1 files changed, 707 insertions, 135 deletions
diff --git a/dw/textblock.cc b/dw/textblock.cc
index 2c4ca20b..91f9a82e 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -25,13 +25,14 @@
#include "../lout/debug.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;
@@ -228,6 +229,7 @@ Textblock::Textblock (bool limitTextWidth)
setFlags (USES_HINTS);
setButtonSensitive(true);
+ containingBlock = NULL;
hasListitemValue = false;
innerPadding = 0;
line1Offset = 0;
@@ -250,15 +252,14 @@ Textblock::Textblock (bool limitTextWidth)
nonTemporaryLines = 0;
words = new misc::NotSoSimpleVector <Word> (1);
anchors = new misc::SimpleVector <Anchor> (1);
-
- //DBG_OBJ_SET_NUM(this, "num_lines", num_lines);
+ outOfFlowMgr = NULL;
wrapRefLines = wrapRefParagraphs = -1;
- //DBG_OBJ_SET_NUM(this, "last_line_width", last_line_width);
- //DBG_OBJ_SET_NUM(this, "last_line_par_min", last_line_par_min);
- //DBG_OBJ_SET_NUM(this, "last_line_par_max", last_line_par_max);
- //DBG_OBJ_SET_NUM(this, "wrap_ref", wrap_ref);
+ DBG_OBJ_SET_NUM ("lines.size", lines->size ());
+ DBG_OBJ_SET_NUM ("words.size", words->size ());
+ DBG_OBJ_SET_NUM ("wrapRefLines", wrapRefLines);
+ DBG_OBJ_SET_NUM ("wrapRefParagraphs", wrapRefParagraphs);
hoverLink = -1;
@@ -267,6 +268,8 @@ Textblock::Textblock (bool limitTextWidth)
availAscent = 100;
availDescent = 0;
+ verticalOffset = 0;
+
this->limitTextWidth = limitTextWidth;
for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
@@ -276,6 +279,8 @@ Textblock::Textblock (bool limitTextWidth)
hlEnd[layer].index = 0;
hlEnd[layer].nChar = 0;
}
+
+ initNewLine ();
}
Textblock::~Textblock ()
@@ -288,8 +293,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? */
removeWordImgRenderer (i);
removeSpaceImgRenderer (i);
@@ -309,6 +315,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;
@@ -323,7 +332,8 @@ Textblock::~Textblock ()
*/
void Textblock::sizeRequestImpl (core::Requisition *requisition)
{
- PRINTF ("[%p] SIZE_REQUEST: ...\n", this);
+ DBG_OBJ_MSG ("resize", 0, "<b>sizeRequestImpl</b> ()");
+ DBG_OBJ_MSG_START ();
rewrap ();
showMissingLines ();
@@ -331,18 +341,18 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
if (lines->size () > 0) {
Line *lastLine = lines->getRef (lines->size () - 1);
requisition->width = lastLine->maxLineWidth;
-
- PRINTF ("[%p] SIZE_REQUEST: lastLine->maxLineWidth = %d\n",
- this, lastLine->maxLineWidth);
-
- PRINTF ("[%p] SIZE_REQUEST: lines[0]->boxAscent = %d\n",
- this, lines->getRef(0)->boxAscent);
- PRINTF ("[%p] SIZE_REQUEST: lines[%d]->top = %d\n",
- this, lines->size () - 1, lastLine->top);
- PRINTF ("[%p] SIZE_REQUEST: lines[%d]->boxAscent = %d\n",
- this, lines->size () - 1, lastLine->boxAscent);
- PRINTF ("[%p] SIZE_REQUEST: lines[%d]->boxDescent = %d\n",
- this, lines->size () - 1, lastLine->boxDescent);
+
+ DBG_OBJ_MSGF ("resize", 1, "lines[%d]->maxLineWidth = %d",
+ lines->size () - 1, lastLine->maxLineWidth);
+
+ DBG_OBJ_MSGF ("resize", 1, "lines[0]->boxAscent = %d",
+ lines->getRef(0)->boxAscent);
+ DBG_OBJ_MSGF ("resize", 1, "lines[%d]->top = %d",
+ lines->size () - 1, lastLine->top);
+ DBG_OBJ_MSGF ("resize", 1, "lines[%d]->boxAscent = %d",
+ lines->size () - 1, lastLine->boxAscent);
+ DBG_OBJ_MSGF ("resize", 1, "lines[%d]->boxDescent = %d",
+ lines->size () - 1, lastLine->boxDescent);
/* Note: the breakSpace of the last line is ignored, so breaks
at the end of a textblock are not visible. */
@@ -356,18 +366,42 @@ void Textblock::sizeRequestImpl (core::Requisition *requisition)
requisition->descent = 0;
}
- PRINTF ("[%p] SIZE_REQUEST: inner padding = %d, boxDiffWidth = %d\n",
- this, innerPadding, getStyle()->boxDiffWidth ());
+ DBG_OBJ_MSGF ("resize", 1, "inner padding = %d, boxDiffWidth = %d",
+ innerPadding, getStyle()->boxDiffWidth ());
requisition->width += innerPadding + getStyle()->boxDiffWidth ();
- requisition->ascent += getStyle()->boxOffsetY ();
+ requisition->ascent += verticalOffset + getStyle()->boxOffsetY ();
requisition->descent += getStyle()->boxRestHeight ();
- if (requisition->width < availWidth)
+ // 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.
+
+ DBG_OBJ_MSGF ("resize", 1, "before considering OOF widgets: %d * %d + %d",
+ requisition->width, requisition->ascent, requisition->descent);
+
+ if (outOfFlowMgr) {
+ int oofWidth, oofHeight;
+ outOfFlowMgr->getSize (&oofWidth, &oofHeight);
+ requisition->width = misc::max (requisition->width, oofWidth);
+ if (oofHeight > requisition->ascent + requisition->descent)
+ requisition->descent = oofHeight - requisition->ascent;
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "before considering availWidth: %d * %d + %d",
+ requisition->width, requisition->ascent, requisition->descent);
+
+ if (requisition->width < availWidth) {
requisition->width = availWidth;
+ DBG_OBJ_MSGF ("resize", 1, "adjusting to availWidth => %d",
+ requisition->width);
+ }
- PRINTF ("[%p] SIZE_REQUEST: %d x %d + %d\n", this, requisition->width,
- requisition->ascent, requisition->descent);
+ DBG_OBJ_MSGF ("resize", 1, "=> %d * %d + %d",
+ requisition->width, requisition->ascent, requisition->descent);
+
+ DBG_OBJ_MSG_END ();
}
/**
@@ -375,7 +409,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 {
@@ -405,7 +439,8 @@ void Textblock::getWordExtremes (Word *word, core::Extremes *extremes)
void Textblock::getExtremesImpl (core::Extremes *extremes)
{
- PRINTF ("[%p] GET_EXTREMES ...\n", this);
+ DBG_OBJ_MSG ("resize", 0, "<b>getExtremesImpl</b>");
+ DBG_OBJ_MSG_START ();
fillParagraphs ();
@@ -423,8 +458,22 @@ void Textblock::getExtremesImpl (core::Extremes *extremes)
extremes->minWidth += diff;
extremes->maxWidth += diff;
- PRINTF ("[%p] GET_EXTREMES => %d / %d\n",
- this, extremes->minWidth, extremes->maxWidth);
+ if (outOfFlowMgr) {
+ int oofMinWidth, oofMaxWidth;
+ outOfFlowMgr->getExtremes (&oofMinWidth, &oofMaxWidth);
+
+ DBG_OBJ_MSGF ("resize", 1, "extremes: %d / %d, corrected: %d / %d",
+ extremes->minWidth, extremes->maxWidth,
+ oofMinWidth, oofMaxWidth);
+
+ extremes->minWidth = misc::max (extremes->minWidth, oofMinWidth);
+ extremes->maxWidth = misc::max (extremes->maxWidth, oofMaxWidth);
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "=> %d / %d",
+ extremes->minWidth, extremes->maxWidth);
+
+ DBG_OBJ_MSG_END ();
}
@@ -436,6 +485,9 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
showMissingLines ();
+ if(outOfFlowMgr)
+ outOfFlowMgr->sizeAllocateStart (allocation);
+
int lineIndex, wordIndex;
Line *line;
Word *word;
@@ -449,7 +501,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++) {
@@ -459,7 +511,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:
@@ -473,6 +525,7 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
lineYOffsetCanvasAllocation (line, allocation)
+ (line->boxAscent - word->size.ascent)
- word->content.widget->getStyle()->margin.top;
+
childAllocation.width = word->size.width;
childAllocation.ascent = word->size.ascent
+ word->content.widget->getStyle()->margin.top;
@@ -531,11 +584,17 @@ void Textblock::sizeAllocateImpl (core::Allocation *allocation)
}
}
+ if(outOfFlowMgr)
+ outOfFlowMgr->sizeAllocateEnd ();
+
for (int i = 0; i < anchors->size(); i++) {
Anchor *anchor = anchors->getRef(i);
int y;
- if (anchor->wordIndex >= words->size()) {
+ if (anchor->wordIndex >= words->size() ||
+ // Also regard not-yet-existing lines.
+ lines->size () <= 0 ||
+ anchor->wordIndex > lines->getLastRef()->lastWord) {
y = allocation->y + allocation->ascent + allocation->descent;
} else {
Line *line = lines->getRef(findLineOfWord (anchor->wordIndex));
@@ -561,47 +620,122 @@ void Textblock::resizeDrawImpl ()
void Textblock::markSizeChange (int ref)
{
- PRINTF ("[%p] MARK_SIZE_CHANGE (%d): %d => ...\n", this, ref, wrapRefLines);
+ DBG_OBJ_MSGF ("resize", 0, "<b>markSizeChange</b> (%d)", ref);
+ DBG_OBJ_MSG_START ();
- /* 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->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);
+ DBG_OBJ_SET_NUM ("wrapRefLines", wrapRefLines);
+
+ // 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);
+ }
- // 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);
+ DBG_OBJ_MSG_END ();
}
void Textblock::markExtremesChange (int ref)
{
- 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);
+ DBG_OBJ_MSGF ("resize", 1, "<b>markExtremesChange</b> (%d)", ref);
+ DBG_OBJ_MSG_START ();
+
+ 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));
+ }
+
+ DBG_OBJ_SET_NUM ("wrapRefParagraphs", wrapRefParagraphs);
}
- PRINTF (" ... => %d\n", wrapRefParagraphs);
+ DBG_OBJ_MSG_END ();
+}
+
+void Textblock::notifySetAsTopLevel()
+{
+ PRINTF ("%p becomes toplevel\n", this);
+ containingBlock = this;
+ PRINTF ("-> %p is its own containing block\n", this);
+}
+
+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::notifySetParent ()
+{
+ PRINTF ("%p becomes a child of %p\n", this, getParent());
+
+ // Search for containing Box.
+ containingBlock = NULL;
+
+ for (Widget *widget = this; widget != NULL && containingBlock == NULL;
+ widget = widget->getParent())
+ if (isContainingBlock (widget)) {
+ containingBlock = (Textblock*)widget;
+
+ if (containingBlock == this) {
+ 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)
@@ -609,43 +743,43 @@ void Textblock::setWidth (int width)
/* If limitTextWidth is set to YES, a queueResize() may also be
* necessary. */
if (availWidth != width || limitTextWidth) {
- //DEBUG_MSG(DEBUG_REWRAP_LEVEL,
- // "setWidth: Calling queueResize, "
- // "in page with %d word(s)\n",
- // words->size());
+ DBG_OBJ_MSGF ("resize", 0, "<b>setWidth</b> (%d)", width);
+ DBG_OBJ_MSG_START ();
availWidth = width;
- queueResize (0, false);
+ queueResize (OutOfFlowMgr::createRefNormalFlow (0), false);
mustQueueResize = false;
redrawY = 0;
+
+ DBG_OBJ_MSG_END ();
}
}
void Textblock::setAscent (int ascent)
{
if (availAscent != ascent) {
- //DEBUG_MSG(DEBUG_REWRAP_LEVEL,
- // "setAscent: Calling queueResize, "
- // "in page with %d word(s)\n",
- // words->size());
+ DBG_OBJ_MSGF ("resize", 0, "<b>setAscent</b> (%d)", ascent);
+ DBG_OBJ_MSG_START ();
availAscent = ascent;
- queueResize (0, false);
+ queueResize (OutOfFlowMgr::createRefNormalFlow (0), false);
mustQueueResize = false;
+
+ DBG_OBJ_MSG_END ();
}
}
void Textblock::setDescent (int descent)
{
if (availDescent != descent) {
- //DEBUG_MSG(DEBUG_REWRAP_LEVEL,
- // "setDescent: Calling queueResize, "
- // "in page with %d word(s)\n",
- // words->size());
+ DBG_OBJ_MSGF ("resize", 0, "<b>setDescent</b> (%d)", descent);
+ DBG_OBJ_MSG_START ();
availDescent = descent;
- queueResize (0, false);
+ queueResize (OutOfFlowMgr::createRefNormalFlow (0), false);
mustQueueResize = false;
+
+ DBG_OBJ_MSG_END ();
}
}
@@ -753,7 +887,8 @@ bool Textblock::sendSelectionEvent (core::SelectionState::EventType eventType,
wordIndex = words->size () - 1;
charPos = core::SelectionState::END_OF_WORD;
} else {
- Line *line = lines->getRef (findLineIndex (event->yWidget));
+ Line *line =
+ lines->getRef (findLineIndexWhenAllocated (event->yWidget));
// Pointer within the break space?
if (event->yWidget >
@@ -761,11 +896,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;
@@ -860,8 +995,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;
@@ -894,7 +1030,25 @@ void Textblock::calcWidgetSize (core::Widget *widget, core::Requisition *size)
availDescent = this->availDescent;
if (widget->usesHints ()) {
- widget->setWidth (availWidth);
+ // This is a simplified version of calcAvailWidth (see there for
+ // more details). Until recently, the *attribute* availWidth was
+ // used, widthout any corrections. To limit the damage, only
+ // includde left and right border (by floats), until the Great
+ // Redesign Of Widget Sizes (GROWS).
+ int corrAvailWidth;
+ // Textblocks keep track of borders themselves, so they get the
+ // total available width. (Should once replaced by something
+ // like OOFAware.)
+ if (widget->instanceOf (Textblock::CLASS_ID))
+ corrAvailWidth = availWidth;
+ else
+ corrAvailWidth =
+ misc::max (availWidth - (newLineLeftBorder + newLineRightBorder),
+ 0);
+
+ PRINTF ("setWidth (%d) for the %s %p\n",
+ corrAvailWidth, widget->getClassName(), widget);
+ widget->setWidth (corrAvailWidth);
widget->setAscent (availAscent);
widget->setDescent (availDescent);
widget->sizeRequest (size);
@@ -1245,7 +1399,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;
@@ -1256,10 +1410,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;
@@ -1303,10 +1457,36 @@ void Textblock::drawLine (Line *line, core::View *view, core::Rectangle *area)
}
/**
- * Find the first line index that includes y, relative to top of widget.
+ * Find the first line index that includes y, which is given in widget
+ * coordinates.
*/
int Textblock::findLineIndex (int y)
{
+ return wasAllocated () ?
+ findLineIndexWhenAllocated (y) : findLineIndexWhenNotAllocated (y);
+}
+
+int Textblock::findLineIndexWhenNotAllocated (int y)
+{
+ if (lines->size() == 0)
+ return -1;
+ else
+ return findLineIndex (y,
+ lines->getRef(0)->boxAscent + verticalOffset +
+ getStyle()->boxOffsetY());
+}
+
+int Textblock::findLineIndexWhenAllocated (int y)
+{
+ assert (wasAllocated ());
+ return findLineIndex (y, allocation.ascent);
+}
+
+int Textblock::findLineIndex (int y, int ascent)
+{
+ core::Allocation alloc;
+ alloc.ascent = ascent; // More is not needed.
+
int maxIndex = lines->size () - 1;
int step, index, low = 0;
@@ -1314,12 +1494,12 @@ int Textblock::findLineIndex (int y)
while ( step > 1 ) {
index = low + step;
if (index <= maxIndex &&
- lineYOffsetWidgetI (index) <= y)
+ lineYOffsetWidgetIAllocation (index, &alloc) <= y)
low = index;
step = (step + 1) >> 1;
}
- if (low < maxIndex && lineYOffsetWidgetI (low + 1) <= y)
+ if (low < maxIndex && lineYOffsetWidgetIAllocation (low + 1, &alloc) <= y)
low++;
/*
@@ -1340,12 +1520,13 @@ int Textblock::findLineIndex (int y)
*/
int Textblock::findLineOfWord (int wordIndex)
{
- int high = lines->size () - 1, index, low = 0;
-
- // TODO regard also not-yet-existing lines?
- if (wordIndex < 0 || wordIndex >= words->size ())
+ if (wordIndex < 0 || wordIndex >= words->size () ||
+ // Also regard not-yet-existing lines.
+ lines->size () <= 0 || wordIndex > lines->getLastRef()->lastWord)
return -1;
+ int high = lines->size () - 1, index, low = 0;
+
while (true) {
index = (low + high) / 2;
if (wordIndex >= lines->getRef(index)->firstWord) {
@@ -1396,14 +1577,14 @@ Textblock::Word *Textblock::findWord (int x, int y, bool *inSpace)
*inSpace = false;
- if ((lineIndex = findLineIndex (y)) >= lines->size ())
+ if ((lineIndex = findLineIndexWhenAllocated (y)) >= lines->size ())
return NULL;
line = lines->getRef (lineIndex);
yWidgetBase = lineYOffsetWidget (line) + line->boxAscent;
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;
@@ -1438,9 +1619,17 @@ void Textblock::draw (core::View *view, core::Rectangle *area)
int lineIndex;
Line *line;
- drawWidgetBox (view, area, false);
+ // Instead of drawWidgetBox, use drawBox to include verticalOffset.
+ if (getParent() == NULL) {
+ // The toplevel (parent == NULL) widget is a special case, which
+ // we leave to drawWidgetBox; verticalOffset will here always 0.
+ assert (verticalOffset == 0);
+ drawWidgetBox (view, area, false);
+ } else
+ drawBox (view, getStyle(), area, 0, verticalOffset, allocation.width,
+ getHeight() - verticalOffset, false);
- lineIndex = findLineIndex (area->y);
+ lineIndex = findLineIndexWhenAllocated (area->y);
for (; lineIndex < lines->size (); lineIndex++) {
line = lines->getRef (lineIndex);
@@ -1449,6 +1638,9 @@ void Textblock::draw (core::View *view, core::Rectangle *area)
drawLine (line, view, area);
}
+
+ if(outOfFlowMgr)
+ outOfFlowMgr->draw(view, area);
}
/**
@@ -1458,6 +1650,7 @@ Textblock::Word *Textblock::addWord (int width, int ascent, int descent,
short flags, core::style::Style *style)
{
words->increase ();
+ DBG_OBJ_SET_NUM ("words.size", words->size ());
int wordNo = words->size () - 1;
initWord (wordNo);
fillWord (wordNo, width, ascent, descent, flags, style);
@@ -1936,6 +2129,16 @@ void Textblock::addText0 (const char *text, size_t len, short flags,
word->content.type = core::Content::TEXT;
word->content.text = layout->textZone->strndup(text, len);
+ DBG_OBJ_ARRATTRSET_SYM ("words", words->size () - 1, "type", "TEXT");
+ DBG_OBJ_ARRATTRSET_STR ("words", words->size () - 1,
+ "text/widget/breakSpace", word->content.text);
+
+ // The following debug message may be useful to identify the
+ // different textblocks.
+
+ //if (words->size() == 1)
+ // printf ("[%p] first word: '%s'\n", this, text);
+
processWord (words->size () - 1);
}
@@ -1944,28 +2147,59 @@ 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 (word %d) ...\n",
+ widget->getClassName(), widget, this, words->size());
- word->content.type = core::Content::WIDGET;
- word->content.widget = widget;
+ if (containingBlock->outOfFlowMgr == NULL) {
+ containingBlock->outOfFlowMgr = new OutOfFlowMgr (containingBlock);
+ DBG_OBJ_ASSOC (containingBlock, containingBlock->outOfFlowMgr);
+ }
+
+ if (OutOfFlowMgr::isWidgetHandledByOOFM (widget)) {
+ PRINTF (" -> out of flow.\n");
+
+ widget->setParent (containingBlock);
+ widget->setGenerator (this);
+ containingBlock->outOfFlowMgr->addWidgetOOF (widget, this,
+ words->size ());
+ Word *word = addWord (0, 0, 0, 0, style);
+ word->content.type = core::Content::WIDGET_OOF_REF;
+ word->content.widget = widget;
+ word->style = style;
+
+ DBG_OBJ_ARRATTRSET_SYM ("words", words->size () - 1, "type",
+ "WIDGET_OOF_REF");
+ DBG_OBJ_ARRATTRSET_PTR ("words", words->size () - 1,
+ "text/widget/breakSpace", word->content.widget);
+ } else {
+ PRINTF (" -> within flow.\n");
- //DBG_OBJ_ARRSET_PTR (page, "words.%d.content.widget", words->size() - 1,
- // word->content.widget);
+ widget->setParent (this);
+
+ // TODO Replace (perhaps) later "textblock" by "OOF aware widget".
+ if (widget->instanceOf (Textblock::CLASS_ID))
+ containingBlock->outOfFlowMgr->addWidgetInFlow ((Textblock*)widget,
+ this, words->size ());
+
+ 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;
+
+ DBG_OBJ_ARRATTRSET_SYM ("words", words->size () - 1, "type",
+ "WIDGET_IN_FLOW");
+ DBG_OBJ_ARRATTRSET_PTR ("words", words->size () - 1,
+ "text/widget/breakSpace", word->content.widget);
+ }
processWord (words->size () - 1);
//DBG_OBJ_SET_NUM (word->content.widget, "parent_ref",
@@ -2067,8 +2301,10 @@ void Textblock::fillSpace (int wordNo, core::style::Style *style)
// TODO: This line does not work: addBreakOption (word, style);
- // Do not override a previously set break penalty.
- if (!word->content.space) {
+ if (// Do not override a previously set break penalty:
+ !word->content.space &&
+ // OOF references are considered specially, and must not have a space:
+ word->content.type != core::Content::WIDGET_OOF_REF) {
setBreakOption (word, style, 0, 0, false);
word->content.space = true;
@@ -2140,7 +2376,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
@@ -2149,23 +2385,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 =
@@ -2174,7 +2410,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;
}
}
@@ -2182,6 +2419,7 @@ void Textblock::addParbreak (int space, core::style::Style *style)
}
/* Otherwise continue to examine parents. */
}
+
/* Return in any case. */
return;
}
@@ -2205,6 +2443,11 @@ void Textblock::addParbreak (int space, core::style::Style *style)
word->content.type = core::Content::BREAK;
word->badnessAndPenalty.setPenalty (PENALTY_FORCE_BREAK);
word->content.breakSpace = space;
+
+ DBG_OBJ_ARRATTRSET_SYM ("words", words->size () - 1, "type", "BREAK");
+ DBG_OBJ_ARRATTRSET_NUM ("words", words->size () - 1,
+ "text/widget/breakSpace", word->content.breakSpace);
+
processWord (words->size () - 1);
}
@@ -2230,10 +2473,14 @@ void Textblock::addLinebreak (core::style::Style *style)
word->content.type = core::Content::BREAK;
word->badnessAndPenalty.setPenalty (PENALTY_FORCE_BREAK);
word->content.breakSpace = 0;
+
+ DBG_OBJ_ARRATTRSET_SYM ("words", words->size () - 1, "type", "BREAK");
+ DBG_OBJ_ARRATTRSET_NUM ("words", words->size () - 1,
+ "text/widget/breakSpace", word->content.breakSpace);
+
processWord (words->size () - 1);
}
-
/**
* \brief Search recursively through widget.
*
@@ -2242,6 +2489,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;
@@ -2252,7 +2503,15 @@ core::Widget *Textblock::getWidgetAtPoint(int x, int y, int level)
return NULL;
}
- lineIndex = findLineIndex (y - allocation.y);
+ // 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 = findLineIndexWhenAllocated (y - allocation.y);
if (lineIndex < 0 || lineIndex >= lines->size ()) {
return this;
@@ -2263,7 +2522,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);
@@ -2303,12 +2562,14 @@ void Textblock::handOverBreak (core::style::Style *style)
*/
void Textblock::flush ()
{
- PRINTF ("[%p] FLUSH => %s (parentRef = %d)\n",
- this, mustQueueResize ? "true" : "false", parentRef);
-
if (mustQueueResize) {
+ DBG_OBJ_MSG ("resize", 0, "<b>flush</b> (mustQueueResize set)");
+ DBG_OBJ_MSG_START ();
+
queueResize (-1, true);
mustQueueResize = false;
+
+ DBG_OBJ_MSG_END ();
}
}
@@ -2344,7 +2605,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,
@@ -2396,4 +2657,315 @@ void Textblock::queueDrawRange (int index1, int index2)
}
}
+void Textblock::setVerticalOffset (int verticalOffset)
+{
+ if (this->verticalOffset != verticalOffset) {
+ this->verticalOffset = verticalOffset;
+ mustQueueResize = true;
+ queueDraw (); // Could perhaps be optimized.
+ }
+}
+
+/**
+ * Called by dw::OutOfFlowMgr when the border has changed due to a
+ * float (or some floats).
+ *
+ * "y", which given in widget coordinates, denotes the minimal
+ * position (when more than one float caused this), "vloat" the
+ * floating widget belonging to "y".
+ */
+void Textblock::borderChanged (int y, Widget *vloat)
+{
+ DBG_OBJ_MSGF ("resize", 0, "<b>borderChanged</b> (%d, %p)", y, vloat);
+ DBG_OBJ_MSG_START ();
+
+ int lineIndex = findLineIndex (y);
+ DBG_OBJ_MSGF ("resize", 1, "Line index: %d (of %d).",
+ lineIndex, lines->size ());
+
+ // Nothing to do at all, when lineIndex >= lines->size (),
+ // i. e. the change is below the bottom of this widget.
+ if (lineIndex < lines->size ()) {
+ int wrapLineIndex;
+ if (lineIndex < 0)
+ // Rewrap all.
+ wrapLineIndex = 0;
+ else
+ wrapLineIndex = lineIndex;
+
+ DBG_OBJ_MSGF ("resize", 1, "Rewrapping from line %d (of %d).",
+ wrapLineIndex, lines->size ());
+
+ if (vloat->getGenerator() == this) {
+ bool found = false;
+ // Sometimes, the respective word is not yet part of a
+ // line. Nothing to do, but because of the assertion below
+ // (and also for performace reasons) this should be
+ // considered. TODO: Integrate this below.
+ for (int wordIndex =
+ lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0;
+ !found && wordIndex < words->size(); wordIndex++) {
+ Word *word = words->getRef (wordIndex);
+ if (word->content.type == core::Content::WIDGET_OOF_REF &&
+ word->content.widget == vloat)
+ found = true;
+ }
+
+ // We search for the line of the float reference. There are
+ // two cases when this is not the line corresponsing to y:
+ //
+ // (1) When the float was moved down, due to collisions with
+ // other floats: in this case, the line number gets
+ // smaller (since the float reference is before).
+ //
+ // (2) In some cases, the line number may become larger, due
+ // to the per-line optimization of the words: initially,
+ // lines->size() - 1 is assigned, but it may happen that
+ // the float reference is put into another line.
+ //
+ // Only in the first case, a correction is neccessary, but a
+ // test for the second case is useful. (TODO: I've forgotten
+ // why a correction is neccessary.)
+ //
+ // Searched is done in the following order:
+ //
+ // - wrapLineIndex,
+ // - wrapLineIndex - 1,
+ // - wrapLineIndex + 1,
+ // - wrapLineIndex - 2,
+ // - wrapLineIndex + 2,
+ //
+ // etc. until either the float reference has been found or
+ // all lines have been searched (the latter triggers an
+ // abortion).
+
+ bool exceedsBeginning = false, exceedsEnd = false;
+ for (int i = 0; !found; i++) {
+ bool exceeds;
+ int lineIndex2;
+ if (i % 2 == 0) {
+ // even: +0, +1, +2, ...
+ lineIndex2 = wrapLineIndex + i / 2;
+ if (i > 0)
+ exceeds = exceedsEnd = lineIndex2 >= lines->size ();
+ else
+ exceeds = exceedsEnd = false;
+ } else {
+ // odd: -1, -2, ...
+ lineIndex2 = wrapLineIndex - (i + 1) / 2;
+ exceeds = exceedsBeginning = lineIndex2 < 0;
+ }
+
+ if (exceedsBeginning && exceedsEnd)
+ break;
+
+ if (!exceeds) {
+ Line *line = lines->getRef (lineIndex2);
+ for (int wordIndex = line->firstWord;
+ !found && wordIndex <= line->lastWord; wordIndex++) {
+ Word *word = words->getRef (wordIndex);
+ if (word->content.type == core::Content::WIDGET_OOF_REF &&
+ word->content.widget == vloat) {
+ found = true;
+ // Correct only by smaller values (case (1) above):
+ wrapLineIndex = misc::min (wrapLineIndex, lineIndex2);
+ }
+ }
+ }
+ }
+
+ if (!found)
+ printBorderChangedErrorAndAbort (y, vloat, wrapLineIndex);
+ }
+
+ DBG_OBJ_MSGF ("resize", 1, "Corrected to line %d.", wrapLineIndex);
+
+ queueResize (OutOfFlowMgr::createRefNormalFlow (wrapLineIndex), true);
+
+ // Notice that the line no. wrapLineIndex may not exist yet.
+ if (wrapLineIndex == 0)
+ lastWordDrawn = misc::min (lastWordDrawn, -1);
+ else
+ lastWordDrawn = misc::min (lastWordDrawn,
+ lines->getRef(wrapLineIndex - 1)->lastWord);
+ }
+
+ DBG_OBJ_MSG_END ();
+}
+
+void Textblock::printBorderChangedErrorAndAbort (int y, Widget *vloat,
+ int wrapLineIndex)
+{
+ // TODO Should be adjusted to recent changes in borderChanged().
+
+ printf ("*** This call failed! ***\n");
+ printf ("[%p] borderChanged (%d, %p (%s))\n",
+ this, y, vloat, vloat->getClassName());
+ printf (" Initial wrapLineIndex = line %d (of %d lines). "
+ "Has to be corrected.\n", wrapLineIndex, lines->size ());
+
+ printf (" search non-existing line (from %d to %d):\n",
+ lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0,
+ words->size() - 1);
+ for (int wordIndex =
+ lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0;
+ wordIndex < words->size(); wordIndex++) {
+ printf (" word %d: ", wordIndex);
+ printWordShort (words->getRef (wordIndex));
+ printf ("\n");
+ }
+
+ for (int lineIndex2 = wrapLineIndex; lineIndex2 >= 0;
+ lineIndex2--) {
+ Line *line = lines->getRef (lineIndex2);
+ printf (" searching existing line %d (from %d to %d):\n",
+ lineIndex2, line->firstWord, line->lastWord);
+ for (int wordIndex = line->firstWord;
+ wordIndex <= line->lastWord; wordIndex++) {
+ printf (" word %d: ", wordIndex);
+ printWordShort (words->getRef (wordIndex));
+ printf ("\n");
+ }
+ }
+
+ bool found2 = false;
+ for (int lineIndex2 = wrapLineIndex + 1;
+ !found2 && lineIndex2 < lines->size (); lineIndex2++) {
+ Line *line = lines->getRef (lineIndex2);
+ printf (" could have searched existing line %d "
+ "(from %d to %d):\n",
+ lineIndex2, line->firstWord, line->lastWord);
+ for (int wordIndex = line->firstWord;
+ !found2 && wordIndex <= line->lastWord; wordIndex++) {
+ Word *word = words->getRef (wordIndex);
+ if (word->content.type == core::Content::WIDGET_OOF_REF &&
+ word->content.widget == vloat) {
+ found2 = true;
+ printf (" word %d: ", wordIndex);
+ printWordShort (word);
+ printf ("\n");
+ }
+ }
+ }
+
+ lout::misc::assertNotReached ();
+}
+
+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 ()) {
+ //printf ("[%p] GET_TEXTBLOCK_FOR_LINE (%d, %d)\n",
+ // this, firstWord, lastWord);
+
+ // A textblock is always between two line breaks, and so the
+ // first word of the line.
+ Word *word = words->getRef (firstWord);
+
+ if (word->content.type == core::Content::WIDGET_IN_FLOW &&
+ word->content.widget->instanceOf (Textblock::CLASS_ID)) {
+ //printf (" word %d: ", firstWord);
+ //printWordShort (word);
+ //printf ("\n");
+
+ return (Textblock*)word->content.widget;
+ }
+ }
+
+ //printf (" nothing\n");
+ return NULL;
+}
+
+/**
+ * Includes margin, border, and padding.
+ */
+int Textblock::yOffsetOfPossiblyMissingLine (int lineNo)
+{
+ DBG_OBJ_MSGF ("line.yoffset", 0,
+ "<b>yOffsetOfPossiblyMissingLine</b> (%d <i>of %d</i>)",
+ lineNo, lines->size());
+ DBG_OBJ_MSG_START ();
+
+ int result;
+
+ if (lineNo == 0) {
+ result = verticalOffset + getStyle()->boxOffsetY();
+ DBG_OBJ_MSGF ("line.yoffset", 1, "first line: %d + %d = %d",
+ verticalOffset, getStyle()->boxOffsetY(), result);
+ } else {
+ Line *prevLine = lines->getRef (lineNo - 1);
+ result = verticalOffset + getStyle()->boxOffsetY() +
+ prevLine->top + prevLine->boxAscent + prevLine->boxDescent +
+ prevLine->breakSpace;
+ DBG_OBJ_MSGF ("line.yoffset", 1,
+ "other line: %d + %d + %d + (%d + %d) + %d = %d",
+ verticalOffset, getStyle()->boxOffsetY(),
+ prevLine->top, prevLine->boxAscent, prevLine->boxDescent,
+ prevLine->breakSpace, result);
+ }
+
+ DBG_OBJ_MSG_END ();
+
+ return result;
+}
+
+int Textblock::heightOfPossiblyMissingLine (int lineNo)
+{
+ DBG_OBJ_MSGF ("line.height", 0,
+ "<b>heightOfPossiblyMissingLine</b> (%d <i>of %d</i>)",
+ lineNo, lines->size());
+ DBG_OBJ_MSG_START ();
+
+ int result;
+
+ if (lineNo < lines->size()) {
+ // An existing line.
+
+ Line *line = lines->getRef (lineNo);
+
+ // This is sometimes called within addLine, so that the
+ // condition above is true, but line->boxAscent and
+ // line->boxDescent are not set appropriately. We have to
+ // accumulate the heights then.
+
+ if (line->finished) {
+ DBG_OBJ_MSGF ("line.height", 1,
+ "exists and is finished; height = %d + %d = %d",
+ line->boxAscent, line->boxDescent,
+ line->boxAscent + line->boxDescent);
+ result = line->boxAscent + line->boxDescent;
+ } else {
+ DBG_OBJ_MSG ("line.height", 1, "exist but is not finished");
+ result = misc::max (1, newLineAscent + newLineDescent);
+ }
+ } else if (lineNo == lines->size()) {
+ // The line to be constructed: some words exist, but not the
+ // line. Accumulate the word heights.
+
+ // Old comment: Furthermore, this is in some cases incomplete:
+ // see doc/dw-out-of-flow.doc. -- Still the case?
+
+ DBG_OBJ_MSG ("line.height", 1, "does not exist");
+ result = misc::max (1, newLineAscent + newLineDescent);
+ } else
+ result = 1;
+
+ DBG_OBJ_MSGF ("line.height", 0, "result = %d", result);
+ DBG_OBJ_MSG_END ();
+
+ return result;
+}
+
} // namespace dw