diff options
Diffstat (limited to 'dw/textblock.cc')
-rw-r--r-- | dw/textblock.cc | 455 |
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 |