Dillo v3.1.1-14-g8f67d6e0
Loading...
Searching...
No Matches
textblock.cc
Go to the documentation of this file.
1/*
2 * Dillo Widget
3 *
4 * Copyright 2005-2007, 2012-2014 Sebastian Geerken <sgeerken@dillo.org>
5 * Copyright 2023-2024 Rodrigo Arias Mallo <rodarima@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21
22#include "textblock.hh"
23#include "../lout/msg.h"
24#include "../lout/misc.hh"
25#include "../lout/unicode.hh"
26#include "../lout/debug.hh"
27
28#include <stdio.h>
29#include <math.h> // remove again?
30#include <limits.h>
31
32/*
33 * Local variables
34 */
35/* The tooltip under mouse pointer in current textblock. No ref. hold.
36 * (having one per view looks not worth the extra clutter). */
38
39
40using namespace lout;
41using namespace lout::misc;
42using namespace lout::unicode;
43
44namespace dw {
45
46int Textblock::CLASS_ID = -1;
47
49 int wordNo)
50{
51 //printf ("new WordImgRenderer %p\n", this);
52
53 this->textblock = textblock;
54 this->wordNo = wordNo;
55 dataSet = false;
56}
57
59{
60 //printf ("delete WordImgRenderer %p\n", this);
61}
62
63void Textblock::WordImgRenderer::setData (int xWordWidget, int lineNo)
64{
65 dataSet = true;
66 this->xWordWidget = xWordWidget;
67 this->lineNo = lineNo;
68}
69
71{
72 //print ();
73 //printf ("\n");
74
75 return dataSet && textblock->wasAllocated ()
76 && wordNo < textblock->words->size()
77 && lineNo < textblock->lines->size();
78}
79
80void Textblock::WordImgRenderer::getBgArea (int *x, int *y, int *width,
81 int *height)
82{
83 // TODO Subtract margin and border (padding box)?
84 Line *line = textblock->lines->getRef (lineNo);
85 *x = textblock->allocation.x + this->xWordWidget;
86 *y = textblock->lineYOffsetCanvas (line);
87 *width = textblock->words->getRef(wordNo)->size.width;
88 *height = line->borderAscent + line->borderDescent;
89}
90
91void Textblock::WordImgRenderer::getRefArea (int *xRef, int *yRef,
92 int *widthRef, int *heightRef)
93{
94 // See comment in Widget::drawBox about the reference area.
95 textblock->getPaddingArea (xRef, yRef, widthRef, heightRef);
96}
97
99{
100 return textblock->words->getRef(wordNo)->style;
101}
102
103void Textblock::WordImgRenderer::draw (int x, int y, int width, int height)
104{
105 textblock->queueDrawArea (x - textblock->allocation.x,
106 y - textblock->allocation.y, width, height);
107
108}
109
110void Textblock::SpaceImgRenderer::getBgArea (int *x, int *y, int *width,
111 int *height)
112{
113 WordImgRenderer::getBgArea (x, y, width, height);
114 *x += *width;
115 *width = textblock->words->getRef(wordNo)->effSpace;
116}
117
119{
120 return textblock->words->getRef(wordNo)->spaceStyle;
121}
122
123// ----------------------------------------------------------------------
124
126 // soft hyphen (U+00AD)
127 { "\xc2\xad", true, false, true, PENALTY_HYPHEN, -1 },
128 // simple hyphen-minus: same penalties like automatic or soft hyphens
129 { "-", false, true, true, -1, PENALTY_HYPHEN },
130 // (unconditional) hyphen (U+2010): handled exactly like minus-hyphen.
131 { "\xe2\x80\x90", false, true, true, -1, PENALTY_HYPHEN },
132 // em dash (U+2014): breaks on both sides are allowed (but see below).
133 { "\xe2\x80\x94", false, true, false,
135};
136
137// Standard values are defined here. The values are already multiplied
138// with 100.
139//
140// Some examples (details are described in doc/dw-line-breaking.doc):
141//
142// 0 = Perfect line; as penalty used for normal spaces.
143
144// 1 (100 here) = A justified line with spaces having 150% or 67% of
145// the ideal space width has this as badness.
146//
147// 8 (800 here) = A justified line with spaces twice as wide as
148// ideally has this as badness.
149//
150// The second value is used when the line before ends with a hyphen,
151// dash etc.
152
154 // Penalties for all hyphens.
155 { 100, 800 },
156 // Penalties for a break point *left* of an em-dash: rather large,
157 // so that a break on the *right* side is preferred.
158 { 800, 800 },
159 // Penalties for a break point *right* of an em-dash: like hyphens.
160 { 100, 800 }
161};
162
164
173const char *Textblock::hyphenDrawChar = "-";
174
175void Textblock::setPenaltyHyphen (int penaltyHyphen)
176{
177 penalties[PENALTY_HYPHEN][0] = penaltyHyphen;
178}
179
180void Textblock::setPenaltyHyphen2 (int penaltyHyphen2)
181{
182 penalties[PENALTY_HYPHEN][1] = penaltyHyphen2;
183}
184
185void Textblock::setPenaltyEmDashLeft (int penaltyLeftEmDash)
186{
187 penalties[PENALTY_EM_DASH_LEFT][0] = penaltyLeftEmDash;
188 penalties[PENALTY_EM_DASH_LEFT][1] = penaltyLeftEmDash;
189}
190
191void Textblock::setPenaltyEmDashRight (int penaltyRightEmDash)
192{
193 penalties[PENALTY_EM_DASH_RIGHT][0] = penaltyRightEmDash;
194}
195
196void Textblock::setPenaltyEmDashRight2 (int penaltyRightEmDash2)
197{
198 penalties[PENALTY_EM_DASH_RIGHT][1] = penaltyRightEmDash2;
199}
200
205
207{
208 DBG_OBJ_CREATE ("dw::Textblock");
209 registerName ("dw::Textblock", &CLASS_ID);
210 setButtonSensitive(true);
211
212 hasListitemValue = false;
214 line1Offset = 0;
216 mustQueueResize = false;
217 DBG_OBJ_SET_BOOL ("mustQueueResize", mustQueueResize);
218 redrawY = 0;
219 DBG_OBJ_SET_NUM ("redrawY", redrawY);
220 lastWordDrawn = -1;
221 DBG_OBJ_SET_NUM ("lastWordDrawn", lastWordDrawn);
222
224
225 /*
226 * The initial sizes of lines and words should not be
227 * too high, since this will waste much memory with tables
228 * containing many small cells. The few more calls to realloc
229 * should not decrease the speed considerably.
230 * (Current setting is for minimal memory usage. An interesting fact
231 * is that high values decrease speed due to memory handling overhead!)
232 * TODO: Some tests would be useful.
233 */
234 paragraphs = new misc::SimpleVector <Paragraph> (1);
235 lines = new misc::SimpleVector <Line> (1);
237 words = new misc::NotSoSimpleVector <Word> (1);
238 anchors = new misc::SimpleVector <Anchor> (1);
239
242
243 DBG_OBJ_SET_NUM ("lines.size", lines->size ());
244 DBG_OBJ_SET_NUM ("words.size", words->size ());
245 DBG_OBJ_SET_NUM ("wrapRefLines", wrapRefLines);
246 DBG_OBJ_SET_NUM ("wrapRefParagraphs", wrapRefParagraphs);
247 DBG_OBJ_SET_NUM ("wrapRefLinesFCX", wrapRefLinesFCX);
248 DBG_OBJ_SET_NUM ("wrapRefLinesFCY", wrapRefLinesFCY);
249
250 hoverLink = -1;
251
252 // -1 means undefined.
253 lineBreakWidth = -1;
254 DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
255
256 this->limitTextWidth = limitTextWidth;
257 this->treatAsInline = treatAsInline;
258
259 for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
260 /* hlStart[layer].index > hlEnd[layer].index means no highlighting */
261 hlStart[layer].index = 1;
262 hlStart[layer].nChar = 0;
263 hlEnd[layer].index = 0;
264 hlEnd[layer].nChar = 0;
265
266 DBG_OBJ_ARRATTRSET_NUM ("hlStart", layer, "index", hlStart[layer].index);
267 DBG_OBJ_ARRATTRSET_NUM ("hlStart", layer, "nChar", hlStart[layer].nChar);
268 DBG_OBJ_ARRATTRSET_NUM ("hlEnd", layer, "index", hlEnd[layer].index);
269 DBG_OBJ_ARRATTRSET_NUM ("hlEnd", layer, "nChar", hlEnd[layer].nChar);
270 }
271
273
274 initNewLine ();
275}
276
278{
279 /* make sure not to call a free'd tooltip (very fast overkill) */
280 hoverTooltip = NULL;
281
282 for (int i = 0; i < words->size(); i++)
283 cleanupWord (i);
284
285 for (int i = 0; i < anchors->size(); i++) {
286 Anchor *anchor = anchors->getRef (i);
287 /* This also frees the names (see removeAnchor() and related). */
288 removeAnchor(anchor->name);
289 }
290
291 delete paragraphs;
292 delete lines;
293 delete words;
294 delete anchors;
295
296 /* Make sure we don't own widgets anymore. Necessary before call of
297 parent class destructor. (???) */
298 words = NULL;
299
301}
302
309 Widget **references, int *x, int *y)
310{
311 DBG_OBJ_ENTER ("resize", 0, "sizeRequestImpl", "%d, ...", numPos);
312
313 sizeRequestParams.fill (numPos, references, x, y);
314
315 // We have to rewrap the whole textblock, if (i) the available width (which
316 // is the line break width) has changed, or (ii) if the position within the
317 // float container, and so possibly borders relative to this textblock, have
318 // changed.
319 //
320 // (The latter is a simplification: an over-correct implementation would test
321 // all OOFMs on whether affectsLeftBorder() or affectsRightBorder() returns
322 // true. Also, this may be optimized by distinguishing between floats
323 // generated by this textblock (which would not make rewrapping necessary)
324 // and floats generated by other textblocks (which would).)
325
326 int newLineBreakWidth = getAvailWidth (true);
327 int newFCX, newFCY;
328 bool fcDefined = findSizeRequestReference (OOFM_FLOATS, &newFCX, &newFCY);
329
330 if (newLineBreakWidth != lineBreakWidth ||
331 (fcDefined && (newFCX != wrapRefLinesFCX ||
332 newFCY != wrapRefLinesFCY))) {
333 lineBreakWidth = newLineBreakWidth;
334 wrapRefLines = 0;
335 DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
336 DBG_OBJ_SET_NUM ("wrapRefLines", wrapRefLines);
337
338 if (!fcDefined) {
339 wrapRefLinesFCX = newFCX;
340 wrapRefLinesFCY = newFCY;
341 DBG_OBJ_SET_NUM ("wrapRefLinesFCX", wrapRefLinesFCX);
342 DBG_OBJ_SET_NUM ("wrapRefLinesFCY", wrapRefLinesFCY);
343 }
344 }
345
346 rewrap ();
348
349 if (lines->size () > 0) {
350 Line *firstLine = lines->getRef(0), *lastLine = lines->getLastRef ();
351
352 // Note: the breakSpace of the last line is ignored, so breaks
353 // at the end of a textblock are not visible.
354
356 lastLine->maxLineWidth + leftInnerPadding + boxDiffWidth ();
357
358 // Also regard collapsing of this widget top margin and the top
359 // margin of the first line box:
361 getStyle()->borderWidth.top,
362 getStyle()->margin.top
363 + extraSpace.top,
364 firstLine->borderAscent,
365 firstLine->marginAscent);
366
367 // And here, regard collapsing of this widget bottom margin and the
368 // bottom margin of the last line box:
370 // (BTW, this line:
371 lastLine->top - firstLine->borderAscent + lastLine->borderAscent +
372 // ... is 0 for a block with one line, so special handling
373 // for this case is not necessary.)
375 getStyle()->borderWidth.bottom,
376 getStyle()->margin.bottom + extraSpace.bottom,
377 lastLine->borderDescent, lastLine->marginDescent);
378 } else {
382 }
383
384 if (usesMaxGeneratorWidth ()) {
385 DBG_OBJ_MSGF ("resize", 1,
386 "before considering lineBreakWidth (= %d): %d * (%d + %d)",
391 } else
392 DBG_OBJ_MSG ("resize", 1, "lineBreakWidth needs no consideration");
393
394 DBG_OBJ_MSGF ("resize", 1, "before correction: %d * (%d + %d)",
396
398 false);
399
400 // Dealing with parts out of flow, which may overlap the borders of
401 // the text block. Base lines are ignored here: they do not play a
402 // role (currently) and caring about them (for the future) would
403 // cause too much problems.
404
405 // Notice that the order is not typical: correctRequisition should
406 // be the last call. However, calling correctRequisition after
407 // outOfFlowMgr->getSize may result again in a size which is too
408 // small for floats, so triggering again (and again) the resize
409 // idle function resulting in CPU hogging. See also
410 // getExtremesImpl.
411 //
412 // Is this really what we want? An alternative could be that
413 // OutOfFlowMgr::getSize honours CSS attributes an corrected sizes.
414
416
417 DBG_OBJ_MSGF ("resize", 1, "final: %d * (%d + %d)",
419 DBG_OBJ_LEAVE ();
420}
421
426
431
432int Textblock::calcVerticalBorder (int widgetPadding, int widgetBorder,
433 int widgetMargin, int lineBorderTotal,
434 int lineMarginTotal)
435{
436 DBG_OBJ_ENTER ("resize", 0, "calcVerticalBorder", "%d, %d, %d, %d, %d",
437 widgetPadding, widgetBorder, widgetMargin, lineBorderTotal,
438 lineMarginTotal);
439
440 int result;
441
442 if (widgetPadding == 0 && widgetBorder == 0) {
443 if (lineMarginTotal - lineBorderTotal >= widgetMargin)
444 result = lineMarginTotal;
445 else
446 result = widgetMargin + lineBorderTotal;
447 } else
448 result = lineMarginTotal + widgetPadding + widgetBorder + widgetMargin;
449
450 DBG_OBJ_LEAVE_VAL ("%d", result);
451 return result;
452}
453
466
468{
469 DBG_OBJ_ENTER0 ("resize", 0, "getExtremesSimpl");
470
472
473 if (paragraphs->size () == 0) {
474 /* empty page */
475 extremes->minWidth = 0;
477 extremes->maxWidth = 0;
480 } else {
481 Paragraph *lastPar = paragraphs->getLastRef ();
482 extremes->minWidth = lastPar->maxParMin;
484 extremes->maxWidth = lastPar->maxParMax;
487
488 DBG_OBJ_MSGF ("resize", 1, "paragraphs[%d]->maxParMin = %d (%d)",
489 paragraphs->size () - 1, lastPar->maxParMin,
490 lastPar->maxParMinIntrinsic);
491 DBG_OBJ_MSGF ("resize", 1, "paragraphs[%d]->maxParMax = %d (%d)",
492 paragraphs->size () - 1, lastPar->maxParMax,
493 lastPar->maxParMaxIntrinsic);
494 }
495
496 DBG_OBJ_MSGF ("resize", 0, "after considering paragraphs: %d (%d) / %d (%d)",
499
500 int diff = leftInnerPadding + boxDiffWidth ();
501 extremes->minWidth += diff;
503 extremes->maxWidth += diff;
505 extremes->adjustmentWidth += diff;
506
507 DBG_OBJ_MSGF ("resize", 0, "after adding diff: %d (%d) / %d (%d)",
510
511 // For the order, see similar reasoning in sizeRequestImpl.
512
514
515 DBG_OBJ_MSGF ("resize", 0, "after correction: %d (%d) / %d (%d)",
518
520
521 DBG_OBJ_MSGF ("resize", 0,
522 "finally, after considering OOFM: %d (%d) / %d (%d)",
525 DBG_OBJ_LEAVE ();
526}
527
532
537
539{
540 OOFAwareWidget::notifySetAsTopLevel ();
541
543 DBG_OBJ_SET_NUM ("numSizeReferences", numSizeReferences);
544}
545
547{
548 OOFAwareWidget::notifySetParent ();
549
551 for (int i = 0; i < NUM_OOFM; i++) {
552 if (oofContainer[i] != this) {
553 // avoid dublicates
554 bool found = false;
555 for (int j = 0; !found && j < numSizeReferences; j++)
556 if (oofContainer[i] == oofContainer[j])
557 found = true;
558
559 if (!found)
561 }
562 }
563
564 DBG_OBJ_SET_NUM ("numSizeReferences", numSizeReferences);
565 for (int i = 0; i < numSizeReferences; i++)
566 DBG_OBJ_ARRSET_PTR ("sizeReferences", i, sizeReferences[i]);
567}
568
570{
571 DBG_OBJ_ENTER ("resize", 0, "sizeAllocateImpl", "%d, %d; %d * (%d + %d)",
574
576
578
579 int lineIndex, wordIndex;
580 Line *line;
581 Word *word;
582 int xCursor;
583 core::Allocation childAllocation;
584 core::Allocation *oldChildAllocation;
585
586 if (allocation->x != this->allocation.x ||
587 allocation->y != this->allocation.y ||
588 allocation->width != this->allocation.width) {
589 redrawY = 0;
590 DBG_OBJ_SET_NUM ("redrawY", redrawY);
591 }
592
594
595 for (lineIndex = 0; lineIndex < lines->size (); lineIndex++) {
596 DBG_OBJ_MSGF ("resize", 1, "line %d", lineIndex);
598
599 // Especially for floats, allocation->width may be different
600 // from the line break width, so that for centered and right
601 // text, the offsets have to be recalculated again. However, if
602 // the allocation width is greater than the line break width,
603 // due to wide unbreakable lines (large image etc.), use the
604 // original line break width.
605 //
606 // TODO: test case?
607
609
610 line = lines->getRef (lineIndex);
611 xCursor = line->textOffset;
612
613 DBG_OBJ_MSGF ("resize", 1, "xCursor = %d (initially)", xCursor);
614
615 for (wordIndex = line->firstWord; wordIndex <= line->lastWord;
616 wordIndex++) {
617 word = words->getRef (wordIndex);
618
619 if (wordIndex == lastWordDrawn + 1) {
621 DBG_OBJ_SET_NUM ("redrawY", redrawY);
622 }
623
625 DBG_OBJ_MSGF ("resize", 1,
626 "allocating widget in flow: line %d, word %d",
627 lineIndex, wordIndex);
628
629 // TODO For word->flags & Word::TOPLEFT_OF_LINE, make
630 // allocation consistent with calcSizeOfWidgetInFlow():
631
632 childAllocation.x = xCursor + allocation->x;
633
635 /* align=top:
636 childAllocation.y = line->top + allocation->y;
637 */
638 /* align=bottom (base line) */
639 /* Commented lines break the n2 and n3 test cases at
640 * https://dillo-browser.github.io/old/test/img/ */
641 childAllocation.y = lineYOffsetCanvas (line, allocation)
642 + (line->borderAscent - word->size.ascent);
643
644 childAllocation.width = word->size.width;
645 childAllocation.ascent = word->size.ascent;
646 childAllocation.descent = word->size.descent;
647
648 oldChildAllocation = word->content.widget->getAllocation();
649
650 if (childAllocation.x != oldChildAllocation->x ||
651 childAllocation.y != oldChildAllocation->y ||
652 childAllocation.width != oldChildAllocation->width) {
653 /* The child widget has changed its position or its width
654 * so we need to redraw from this line onwards.
655 */
656 redrawY =
658 DBG_OBJ_SET_NUM ("redrawY", redrawY);
659 if (word->content.widget->wasAllocated ()) {
661 oldChildAllocation->y - this->allocation.y);
662 DBG_OBJ_SET_NUM ("redrawY", redrawY);
663 }
664
665 } else if (childAllocation.ascent + childAllocation.descent !=
666 oldChildAllocation->ascent + oldChildAllocation->descent) {
667 /* The child widget has changed its height. We need to redraw
668 * from where it changed.
669 * It's important not to draw from the line base, because the
670 * child might be a table covering the whole page so we would
671 * end up redrawing the whole screen over and over.
672 * The drawing of the child content is left to the child itself.
673 * However this optimization is only possible if the widget is
674 * the only word in the line apart from an optional BREAK.
675 * Otherwise the height change of the widget could change the
676 * position of other words in the line, requiring a
677 * redraw of the complete line.
678 */
679 if (line->lastWord == line->firstWord ||
680 (line->lastWord == line->firstWord + 1 &&
681 words->getRef (line->lastWord)->content.type ==
683
684 int childChangedY =
685 misc::min(childAllocation.y - allocation->y +
686 childAllocation.ascent + childAllocation.descent,
687 oldChildAllocation->y - this->allocation.y +
688 oldChildAllocation->ascent +
689 oldChildAllocation->descent);
690
691 redrawY = misc::min (redrawY, childChangedY);
692 DBG_OBJ_SET_NUM ("redrawY", redrawY);
693 } else {
694 redrawY =
696 DBG_OBJ_SET_NUM ("redrawY", redrawY);
697 }
698 }
699 word->content.widget->sizeAllocate (&childAllocation);
700 }
701
702 xCursor += (word->size.width + word->effSpace);
703 DBG_OBJ_MSGF ("resize", 1, "xCursor = %d (after word %d)",
704 xCursor, wordIndex);
705 DBG_MSG_WORD ("resize", 1, "<i>that is:</i> ", wordIndex, "");
706 }
707
709 }
710
712
714
715 for (int i = 0; i < anchors->size(); i++) {
716 Anchor *anchor = anchors->getRef(i);
717 int y;
718
719 if (anchor->wordIndex >= words->size() ||
720 // Also regard not-yet-existing lines.
721 lines->size () <= 0 ||
722 anchor->wordIndex > lines->getLastRef()->lastWord) {
724 } else {
725 Line *line = lines->getRef(findLineOfWord (anchor->wordIndex));
726 y = lineYOffsetCanvas (line, allocation);
727 }
728 changeAnchor (anchor->name, y);
729 }
730
731 DBG_OBJ_LEAVE ();
732}
733
734void Textblock::calcExtraSpaceImpl (int numPos, Widget **references, int *x,
735 int *y)
736{
737 DBG_OBJ_ENTER0 ("resize", 0, "Textblock::calcExtraSpaceImpl");
738
739 sizeRequestParams.fill (numPos, references, x, y);
740
741 OOFAwareWidget::calcExtraSpaceImpl (numPos, references, x, y);
742
743 int clearPosition = 0;
744 for (int i = 0; i < NUM_OOFM; i++)
745 if (searchOutOfFlowMgr (i) && findSizeRequestReference (i, NULL, NULL))
746 clearPosition =
747 misc::max (clearPosition,
748 searchOutOfFlowMgr(i)->getClearPosition (this));
749
750 extraSpace.top = misc::max (extraSpace.top, clearPosition);
751
752 DBG_OBJ_LEAVE ();
753}
754
755int Textblock::getAvailWidthOfChild (Widget *child, bool forceValue)
756{
757 DBG_OBJ_ENTER ("resize", 0, "Textblock::getAvailWidthOfChild", "%p, %s",
758 child, forceValue ? "true" : "false");
759
760 int width;
761
762 if (isWidgetOOF (child) && getWidgetOutOfFlowMgr(child) &&
764 width =
765 getWidgetOutOfFlowMgr(child)->getAvailWidthOfChild (child,forceValue);
766 else {
767 if (child->getStyle()->width == core::style::LENGTH_AUTO) {
768 // No width specified: similar to standard implementation (see
769 // there), but "leftInnerPadding" has to be considered, too.
770 DBG_OBJ_MSG ("resize", 1, "no specification");
771 if (forceValue) {
772 width = misc::max (getAvailWidth (true) - boxDiffWidth ()
774 0);
775
776 if (width != -1) {
777 /* Clamp to min-width and max-width if given, taking into
778 * account leftInnerPadding. */
779 int maxWidth = child->calcWidth (child->getStyle()->maxWidth,
780 -1, this, -1, false);
781 if (maxWidth != -1 && width > maxWidth - leftInnerPadding)
782 width = maxWidth - leftInnerPadding;
783
784 int minWidth = child->calcWidth (child->getStyle()->minWidth,
785 -1, this, -1, false);
786 if (minWidth != -1 && width < minWidth - leftInnerPadding)
787 width = minWidth - leftInnerPadding;
788 }
789
790 } else {
791 width = -1;
792 }
793 } else
794 width = Widget::getAvailWidthOfChild (child, forceValue);
795
796 if (forceValue && this == child->getContainer () &&
802 }
803 }
804
805 DBG_OBJ_LEAVE_VAL ("%d", width);
806 return width;
807}
808
810{
811 if (isWidgetOOF(child) && getWidgetOutOfFlowMgr(child) &&
812 getWidgetOutOfFlowMgr(child)->dealingWithSizeOfChild (child))
813 return getWidgetOutOfFlowMgr(child)->getAvailHeightOfChild (child,
814 forceValue);
815 else
816 return Widget::getAvailHeightOfChild (child, forceValue);
817}
818
820{
821 DBG_OBJ_ENTER0 ("resize", 0, "containerSizeChangedForChildren");
822
823 for (int i = 0; i < words->size (); i++) {
824 Word *word = words->getRef (i);
827 }
828
830
831 DBG_OBJ_LEAVE ();
832}
833
835{
836 DBG_OBJ_ENTER ("resize", 0,
837 "Textblock/affectsSizeChangeContainerChild", "%p", child);
838
839 // See Textblock::getAvailWidthOfChild() and Textblock::oofSizeChanged():
840 // Extremes changes affect the size of the child, too:
841 bool ret;
842 if (!usesMaxGeneratorWidth () &&
844 ret = true;
845 else
846 ret = Widget::affectsSizeChangeContainerChild (child);
847
848 DBG_OBJ_LEAVE_VAL ("%s", boolToStr(ret));
849 return ret;
850}
851
853{
854 return true;
855}
856
858{
859 DBG_OBJ_ENTER0 ("draw", 0, "resizeDrawImpl");
860
862 if (lines->size () > 0) {
863 Line *lastLine = lines->getRef (lines->size () - 1);
864 /* Remember the last word that has been drawn so we can ensure to
865 * draw any new added words (see sizeAllocateImpl()).
866 */
867 lastWordDrawn = lastLine->lastWord;
868 DBG_OBJ_SET_NUM ("lastWordDrawn", lastWordDrawn);
869 }
870
871 redrawY = getHeight ();
872 DBG_OBJ_SET_NUM ("redrawY", redrawY);
873
874 DBG_OBJ_LEAVE ();
875}
876
878{
879 DBG_OBJ_ENTER ("resize", 0, "markSizeChange", "%d", ref);
880
881 if (isParentRefOOF (ref))
884 else {
885 /* By the way: ref == -1 may have two different causes: (i) flush()
886 calls "queueResize (-1, true)", when no rewrapping is necessary;
887 and (ii) a word may have parentRef == -1 , when it is not yet
888 added to a line. In the latter case, nothing has to be done
889 now, but addLine(...) will do everything necessary. */
890 if (ref != -1) {
891 if (wrapRefLines == -1)
893 else
896 }
897
898 DBG_OBJ_SET_NUM ("wrapRefLines", wrapRefLines);
899
900 // It seems that sometimes (even without floats) the lines
901 // structure is changed, so that wrapRefLines may refers to a
902 // line which does not exist anymore. Should be examined
903 // again. Until then, setting wrapRefLines to the same value is
904 // a workaround.
905 markExtremesChange (ref);
906 }
907
908 DBG_OBJ_LEAVE ();
909}
910
912{
913 DBG_OBJ_ENTER ("resize", 1, "markExtremesChange", "%d", ref);
914
915 if (isParentRefOOF (ref))
918 else {
919 /* By the way: ref == -1 may have two different causes: (i) flush()
920 calls "queueResize (-1, true)", when no rewrapping is necessary;
921 and (ii) a word may have parentRef == -1 , when it is not yet
922 added to a line. In the latter case, nothing has to be done
923 now, but addLine(...) will do everything necessary. */
924 if (ref != -1) {
925 if (wrapRefParagraphs == -1)
927 else
930 }
931
932 DBG_OBJ_SET_NUM ("wrapRefParagraphs", wrapRefParagraphs);
933 }
934
935 DBG_OBJ_LEAVE ();
936}
937
939{
940 return true;
941}
942
947
952
953/*
954 * Handle motion inside the widget
955 * (special care is necessary when switching from another widget,
956 * because hoverLink and hoverTooltip are meaningless then).
957 */
959{
960 if (event->state & core::BUTTON1_MASK)
962 else {
963 bool inSpace;
964 int linkOld = hoverLink;
966 const Word *word = findWord (event->xWidget, event->yWidget, &inSpace);
967
968 // cursor from word or widget style
969 if (word == NULL) {
970 setCursor (getStyle()->cursor);
971 hoverLink = -1;
972 hoverTooltip = NULL;
973 } else {
974 core::style::Style *style = inSpace ? word->spaceStyle : word->style;
978 }
979
980 // Show/hide tooltip
981 if (tooltipOld != hoverTooltip) {
982 if (tooltipOld)
983 tooltipOld->onLeave ();
984 if (hoverTooltip)
986 } else if (hoverTooltip)
988
989 _MSG("MN tb=%p tooltipOld=%p hoverTooltip=%p\n",
990 this, tooltipOld, hoverTooltip);
991 if (hoverLink != linkOld) {
992 /* LinkEnter with hoverLink == -1 is the same as LinkLeave */
993 return layout->emitLinkEnter (this, hoverLink, -1, -1, -1);
994 } else {
995 return hoverLink != -1;
996 }
997 }
998}
999
1001{
1002 _MSG(" tb=%p, ENTER NotifyImpl hoverTooltip=%p\n", this, hoverTooltip);
1003 /* reset hoverLink so linkEnter is detected */
1004 hoverLink = -2;
1005}
1006
1008{
1009 _MSG(" tb=%p, LEAVE NotifyImpl: hoverTooltip=%p\n", this, hoverTooltip);
1010
1011 /* leaving the viewport can't be handled by motionNotifyImpl() */
1012 if (hoverLink >= 0)
1013 layout->emitLinkEnter (this, -1, -1, -1, -1);
1014
1015 if (hoverTooltip) {
1017 hoverTooltip = NULL;
1018 }
1019}
1020
1026{
1027 DBG_OBJ_ENTER0 ("events", 0, "sendSelectionEvent");
1028
1029 core::Iterator *it;
1030 int wordIndex;
1031 int charPos = 0, link = -1;
1032 bool r;
1033
1034 if (words->size () == 0) {
1035 wordIndex = -1;
1036 } else {
1037 Line *lastLine = lines->getRef (lines->size () - 1);
1038 int yFirst = lineYOffsetCanvas (0);
1039 int yLast = lineYOffsetCanvas (lastLine) + lastLine->borderAscent +
1040 lastLine->borderDescent;
1041 if (event->yCanvas < yFirst) {
1042 // Above the first line: take the first word.
1043 wordIndex = 0;
1044 } else if (event->yCanvas >= yLast) {
1045 // Below the last line: take the last word.
1046 wordIndex = words->size () - 1;
1048 } else {
1049 Line *line =
1050 lines->getRef (findLineIndexWhenAllocated (event->yWidget));
1051
1052 // Pointer within the break space?
1053 if (event->yWidget > (lineYOffsetWidget (line) +
1054 line->borderAscent + line->borderDescent)) {
1055 // Choose this break.
1056 wordIndex = line->lastWord;
1058 } else if (event->xWidget < line->textOffset) {
1059 // Left of the first word in the line.
1060 wordIndex = line->firstWord;
1061 } else {
1062 int nextWordStartX = line->textOffset;
1063
1064 for (wordIndex = line->firstWord;
1065 wordIndex <= line->lastWord;
1066 wordIndex++) {
1067 Word *word = words->getRef (wordIndex);
1068 int wordStartX = nextWordStartX;
1069
1070 nextWordStartX += word->size.width + word->effSpace;
1071
1072 if (event->xWidget >= wordStartX &&
1073 event->xWidget < nextWordStartX) {
1074 // We have found the word.
1075 int yWidgetBase =
1076 lineYOffsetWidget (line) + line->borderAscent;
1077
1078 if (event->xWidget >= nextWordStartX - word->effSpace) {
1080 if (wordIndex < line->lastWord &&
1081 (words->getRef(wordIndex + 1)->content.type !=
1083 (event->yWidget <=
1084 yWidgetBase + word->spaceStyle->font->descent) &&
1085 (event->yWidget >
1086 yWidgetBase - word->spaceStyle->font->ascent)) {
1087 link = word->spaceStyle->x_link;
1088 }
1089 } else {
1090 if (event->yWidget <= yWidgetBase + word->size.descent &&
1091 event->yWidget > yWidgetBase - word->size.ascent) {
1092 link = word->style->x_link;
1093 }
1094 if (word->content.type == core::Content::TEXT) {
1095 int glyphX = wordStartX;
1096 int isStartWord = word->flags & Word::WORD_START;
1097 int isEndWord = word->flags & Word::WORD_END;
1098
1099 while (1) {
1100 int nextCharPos =
1101 layout->nextGlyph (word->content.text, charPos);
1102 // TODO The width of a text is not the sum
1103 // of the widths of the glyphs, because of
1104 // ligatures, kerning etc., so textWidth
1105 // should be applied to the text from 0 to
1106 // nextCharPos. (Or not? See comment below.)
1107
1108 int glyphWidth =
1109 textWidth (word->content.text, charPos,
1110 nextCharPos - charPos, word->style,
1111 isStartWord && charPos == 0,
1112 isEndWord &&
1113 word->content.text[nextCharPos] == 0);
1114 if (event->xWidget > glyphX + glyphWidth) {
1115 glyphX += glyphWidth;
1116 charPos = nextCharPos;
1117 continue;
1118 } else if (event->xWidget >= glyphX + glyphWidth/2){
1119 // On the right half of a character;
1120 // now just look for combining chars
1121 charPos = nextCharPos;
1122 while (word->content.text[charPos]) {
1123 nextCharPos =
1124 layout->nextGlyph (word->content.text,
1125 charPos);
1126 if (textWidth (word->content.text, charPos,
1127 nextCharPos - charPos,
1128 word->style,
1129 isStartWord && charPos == 0,
1130 isEndWord &&
1131 word->content.text[nextCharPos]
1132 == 0))
1133 break;
1134 charPos = nextCharPos;
1135 }
1136 }
1137 break;
1138 }
1139 } else {
1140 // Depends on whether the pointer is within the left or
1141 // right half of the (non-text) word.
1142 if (event->xWidget >= (wordStartX + nextWordStartX) /2)
1144 }
1145 }
1146 break;
1147 }
1148 }
1149 if (wordIndex > line->lastWord) {
1150 // No word found in this line (i.e. we are on the right side),
1151 // take the last of this line.
1152 wordIndex = line->lastWord;
1154 }
1155 }
1156 }
1157 }
1158
1159 DBG_OBJ_MSGF ("events", 1, "wordIndex = %d", wordIndex);
1160 DBG_MSG_WORD ("events", 1, "<i>this is:</i> ", wordIndex, "");
1161
1163 (this, core::Content::maskForSelection (true), wordIndex);
1164 r = selectionHandleEvent (eventType, it, charPos, link, event);
1165 it->unref ();
1166
1167 DBG_OBJ_LEAVE_VAL ("%s", boolToStr(r));
1168 return r;
1169}
1170
1172{
1174}
1175
1177{
1178 return new TextblockIterator (this, mask, atEnd);
1179}
1180
1181/*
1182 * Draw the decorations on a word.
1183 */
1186 int x, int yBase, int width)
1187{
1188 int y, height;
1189
1190 height = 1 + style->font->xHeight / 12;
1192 y = yBase + style->font->descent / 3;
1193 view->drawRectangle (style->color, shading, true, x, y, width, height);
1194 }
1196 y = yBase - style->font->ascent;
1197 view->drawRectangle (style->color, shading, true, x, y, width, height);
1198 }
1200 y = yBase + (style->font->descent - style->font->ascent) / 2 +
1201 style->font->descent / 4;
1202 view->drawRectangle (style->color, shading, true, x, y, width, height);
1203 }
1204}
1205
1206/*
1207 * Draw a string of text
1208 *
1209 * Arguments: ... "isStart" and "isEnd" are true, when the text
1210 * start/end represents the start/end of a "real" text word (before
1211 * hyphenation). This has an effect on text transformation. ("isEnd"
1212 * is not used yet, but here for symmetry.)
1213 */
1215 core::style::Color::Shading shading, int x, int y,
1216 const char *text, int start, int len, bool isStart,
1217 bool isEnd)
1218{
1219 if (len > 0) {
1220 char *str = NULL;
1221
1222 switch (style->textTransform) {
1224 default:
1225 break;
1227 str = layout->textToUpper(text + start, len);
1228 break;
1230 str = layout->textToLower(text + start, len);
1231 break;
1233 // If "isStart" is false, the first letter of "text" is
1234 // not the first letter of the "real" text word, so no
1235 // transformation is necessary.
1236 if (isStart) {
1237 /* \bug No way to know about non-ASCII punctuation. */
1238 bool initial_seen = false;
1239
1240 for (int i = 0; i < start; i++)
1241 if (!ispunct(text[i]))
1242 initial_seen = true;
1243 if (initial_seen)
1244 break;
1245
1246 int after = 0;
1247 text += start;
1248 while (ispunct(text[after]))
1249 after++;
1250 if (text[after])
1251 after = layout->nextGlyph(text, after);
1252 if (after > len)
1253 after = len;
1254
1255 char *initial = layout->textToUpper(text, after);
1256 int newlen = strlen(initial) + len-after;
1257 str = (char *)malloc(newlen + 1);
1258 strcpy(str, initial);
1259 strncpy(str + strlen(str), text+after, len-after);
1260 str[newlen] = '\0';
1261 free(initial);
1262 }
1263 break;
1264 }
1265
1266 view->drawText(style->font, style->color, shading, x, y,
1267 str ? str : text + start, str ? strlen(str) : len);
1268 if (str)
1269 free(str);
1270 }
1271}
1272
1281void Textblock::drawWord (Line *line, int wordIndex1, int wordIndex2,
1282 core::View *view, core::Rectangle *area,
1283 int xWidget, int yWidgetBase)
1284{
1285 core::style::Style *style = words->getRef(wordIndex1)->style;
1286 bool drawHyphen = wordIndex2 == line->lastWord
1287 && (words->getRef(wordIndex2)->flags & Word::DIV_CHAR_AT_EOL);
1288
1289 if (style->hasBackground ()) {
1290 int w = 0;
1291 for (int i = wordIndex1; i <= wordIndex2; i++)
1292 w += words->getRef(i)->size.width;
1293 w += words->getRef(wordIndex2)->hyphenWidth;
1294 drawBox (view, style, area, xWidget, yWidgetBase - line->borderAscent,
1295 w, line->borderAscent + line->borderDescent, false);
1296 }
1297
1298 if (wordIndex1 == wordIndex2 && !drawHyphen) {
1299 // Simple case, where copying in one buffer is not needed.
1300 Word *word = words->getRef (wordIndex1);
1301 drawWord0 (wordIndex1, wordIndex2, word->content.text, word->size.width,
1302 false, style, view, area, xWidget, yWidgetBase);
1303 } else {
1304 // Concatenate all words in a new buffer.
1305 int l = 0, totalWidth = 0;
1306 for (int i = wordIndex1; i <= wordIndex2; i++) {
1307 Word *w = words->getRef (i);
1308 l += strlen (w->content.text);
1309 totalWidth += w->size.width;
1310 }
1311
1312 char text[l + (drawHyphen ? strlen (hyphenDrawChar) : 0) + 1];
1313 int p = 0;
1314 for (int i = wordIndex1; i <= wordIndex2; i++) {
1315 const char * t = words->getRef(i)->content.text;
1316 strcpy (text + p, t);
1317 p += strlen (t);
1318 }
1319
1320 if(drawHyphen) {
1321 for (int i = 0; hyphenDrawChar[i]; i++)
1322 text[p++] = hyphenDrawChar[i];
1323 text[p++] = 0;
1324 }
1325
1326 drawWord0 (wordIndex1, wordIndex2, text, totalWidth, drawHyphen,
1327 style, view, area, xWidget, yWidgetBase);
1328 }
1329}
1330
1334void Textblock::drawWord0 (int wordIndex1, int wordIndex2,
1335 const char *text, int totalWidth, bool drawHyphen,
1337 core::Rectangle *area, int xWidget, int yWidgetBase)
1338{
1339 int xWorld = allocation.x + xWidget;
1340 int yWorldBase;
1341
1342 /* Adjust the text baseline if the word is <SUP>-ed or <SUB>-ed. */
1344 yWidgetBase += style->font->ascent / 3;
1345 else if (style->valign == core::style::VALIGN_SUPER) {
1346 yWidgetBase -= style->font->ascent / 2;
1347 }
1348 yWorldBase = yWidgetBase + allocation.y;
1349
1350 bool isStartTotal = words->getRef(wordIndex1)->flags & Word::WORD_START;
1351 bool isEndTotal = words->getRef(wordIndex2)->flags & Word::WORD_START;
1353 yWorldBase, text, 0, strlen (text), isStartTotal, isEndTotal);
1354
1355 if (style->textDecoration)
1357 yWorldBase, totalWidth);
1358
1359 for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
1360 if (wordIndex1 <= hlEnd[layer].index &&
1361 wordIndex2 >= hlStart[layer].index) {
1362 const int wordLen = strlen (text);
1363 int xStart, width;
1364 int firstCharIdx;
1365 int lastCharIdx;
1366
1367 if (hlStart[layer].index < wordIndex1)
1368 firstCharIdx = 0;
1369 else {
1370 firstCharIdx =
1371 misc::min (hlStart[layer].nChar,
1372 (int)strlen (words->getRef(hlStart[layer].index)
1373 ->content.text));
1374 for (int i = wordIndex1; i < hlStart[layer].index; i++)
1375 // It can be assumed that all words from wordIndex1 to
1376 // wordIndex2 have content type TEXT.
1377 firstCharIdx += strlen (words->getRef(i)->content.text);
1378 }
1379
1380 if (hlEnd[layer].index > wordIndex2)
1381 lastCharIdx = wordLen;
1382 else {
1383 lastCharIdx =
1384 misc::min (hlEnd[layer].nChar,
1385 (int)strlen (words->getRef(hlEnd[layer].index)
1386 ->content.text));
1387 for (int i = wordIndex1; i < hlEnd[layer].index; i++)
1388 // It can be assumed that all words from wordIndex1 to
1389 // wordIndex2 have content type TEXT.
1390 lastCharIdx += strlen (words->getRef(i)->content.text);
1391 }
1392
1393 xStart = xWorld;
1394 if (firstCharIdx)
1395 xStart += textWidth (text, 0, firstCharIdx, style,
1396 isStartTotal,
1397 isEndTotal && text[firstCharIdx] == 0);
1398 // With a hyphen, the width is a bit longer than totalWidth,
1399 // and so, the optimization to use totalWidth is not correct.
1400 if (!drawHyphen && firstCharIdx == 0 && lastCharIdx == wordLen)
1401 width = totalWidth;
1402 else
1403 width = textWidth (text, firstCharIdx,
1404 lastCharIdx - firstCharIdx, style,
1405 isStartTotal && firstCharIdx == 0,
1406 isEndTotal && text[lastCharIdx] == 0);
1407 if (width > 0) {
1408 /* Highlight text */
1409 core::style::Color *wordBgColor;
1410
1411 if (!(wordBgColor = style->backgroundColor))
1412 wordBgColor = getBgColor();
1413
1414 /* Draw background for highlighted text. */
1415 view->drawRectangle (
1416 wordBgColor, core::style::Color::SHADING_INVERSE, true, xStart,
1417 yWorldBase - style->font->ascent, width,
1419
1420 /* Highlight the text. */
1422 yWorldBase, text, firstCharIdx,
1423 lastCharIdx - firstCharIdx,
1424 isStartTotal && firstCharIdx == 0,
1425 isEndTotal && lastCharIdx == wordLen);
1426
1427 if (style->textDecoration)
1429 xStart, yWorldBase, width);
1430 }
1431 }
1432 }
1433}
1434
1435/*
1436 * Draw a space.
1437 */
1438void Textblock::drawSpace(int wordIndex, core::View *view,
1439 core::Rectangle *area, int xWidget, int yWidgetBase)
1440{
1441 Word *word = words->getRef(wordIndex);
1442 int xWorld = allocation.x + xWidget;
1443 int yWorldBase;
1445 bool highlight = false;
1446
1447 /* Adjust the space baseline if it is <SUP>-ed or <SUB>-ed */
1449 yWidgetBase += style->font->ascent / 3;
1450 else if (style->valign == core::style::VALIGN_SUPER) {
1451 yWidgetBase -= style->font->ascent / 2;
1452 }
1453 yWorldBase = allocation.y + yWidgetBase;
1454
1455 for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
1456 if (hlStart[layer].index <= wordIndex &&
1457 hlEnd[layer].index > wordIndex) {
1458 highlight = true;
1459 break;
1460 }
1461 }
1462 if (highlight) {
1463 core::style::Color *spaceBgColor;
1464
1465 if (!(spaceBgColor = style->backgroundColor))
1466 spaceBgColor = getBgColor();
1467
1468 view->drawRectangle (
1469 spaceBgColor, core::style::Color::SHADING_INVERSE, true, xWorld,
1470 yWorldBase - style->font->ascent, word->effSpace,
1472 }
1473 if (style->textDecoration) {
1474 core::style::Color::Shading shading = highlight ?
1477
1478 decorateText(view, style, shading, xWorld, yWorldBase, word->effSpace);
1479 }
1480}
1481
1482/*
1483 * Paint a line
1484 * - x and y are toplevel dw coordinates (Question: what Dw? Changed. Test!)
1485 * - area is used always (ev. set it to event->area)
1486 * - event is only used when is_expose
1487 */
1489 core::DrawingContext *context)
1490{
1491 DBG_OBJ_ENTER ("draw", 0, "drawLine", "..., [%d, %d, %d * %d]",
1492 area->x, area->y, area->width, area->height);
1493
1494 int xWidget = line->textOffset;
1495 int yWidgetBase = lineYOffsetWidget (line) + line->borderAscent;
1496
1497 DBG_OBJ_MSGF ("draw", 1, "line from %d to %d (%d words), at (%d, %d)",
1498 line->firstWord, line->lastWord, words->size (),
1499 xWidget, yWidgetBase);
1500 DBG_MSG_WORD ("draw", 1, "<i>line starts with: </i>", line->firstWord, "");
1501 DBG_MSG_WORD ("draw", 1, "<i>line ends with: </i>", line->lastWord, "");
1502
1504
1505 for (int wordIndex = line->firstWord;
1506 wordIndex <= line->lastWord && xWidget < area->x + area->width;
1507 wordIndex++) {
1508 DBG_MSG_WORD ("draw", 2, "<i>drawing: </i>", wordIndex, "");
1509
1510 Word *word = words->getRef (wordIndex);
1511 int wordSize = word->size.width;
1512
1513 if (xWidget + wordSize + word->hyphenWidth + word->effSpace >= area->x) {
1514 if (word->content.type == core::Content::TEXT ||
1516
1517 if (word->size.width > 0) {
1519 core::Widget *child = word->content.widget;
1520 core::Rectangle childArea;
1522 (child) &&
1523 child->intersects (this, area, &childArea))
1524 child->draw (view, &childArea, context);
1525 } else {
1526 int wordIndex2 = wordIndex;
1527 while (wordIndex2 < line->lastWord &&
1528 (words->getRef(wordIndex2)->flags
1530 word->style == words->getRef(wordIndex2 + 1)->style)
1531 wordIndex2++;
1532
1533 drawWord(line, wordIndex, wordIndex2, view, area,
1534 xWidget, yWidgetBase);
1535 wordSize = 0;
1536 for (int i = wordIndex; i <= wordIndex2; i++)
1537 wordSize += words->getRef(i)->size.width;
1538
1539 wordIndex = wordIndex2;
1540 word = words->getRef(wordIndex);
1541 }
1542 }
1543
1544 if (word->effSpace > 0 && wordIndex < line->lastWord &&
1545 words->getRef(wordIndex + 1)->content.type !=
1547 if (word->spaceStyle->hasBackground ())
1548 drawBox (view, word->spaceStyle, area,
1549 xWidget + wordSize,
1550 yWidgetBase - line->borderAscent, word->effSpace,
1551 line->borderAscent + line->borderDescent, false);
1552 drawSpace (wordIndex, view, area, xWidget + wordSize,
1553 yWidgetBase);
1554 }
1555
1556 }
1557 }
1558 xWidget += wordSize + word->effSpace;
1559 }
1560
1561 DBG_OBJ_MSG_END ();
1562
1563 DBG_OBJ_LEAVE ();
1564}
1565
1575
1577{
1578 if (lines->size() == 0)
1579 return -1;
1580 else
1581 return
1583 getStyle()->borderWidth.top,
1584 getStyle()->margin.top
1585 + extraSpace.top,
1586 lines->getRef(0)->borderAscent,
1587 lines->getRef(0)->marginAscent));
1588}
1589
1591{
1592 assert (wasAllocated ());
1593 return findLineIndex (y, allocation.ascent);
1594}
1595
1596int Textblock::findLineIndex (int y, int ascent)
1597{
1598 DBG_OBJ_ENTER ("events", 0, "findLineIndex", "%d, %d", y, ascent);
1599
1600 core::Allocation alloc;
1601 alloc.ascent = ascent; // More is not needed.
1602
1603 int maxIndex = lines->size () - 1;
1604 int step, index, low = 0;
1605
1606 step = (lines->size() + 1) >> 1;
1607 while ( step > 1 ) {
1608 index = low + step;
1609 if (index <= maxIndex && lineYOffsetWidget (index, &alloc) <= y)
1610 low = index;
1611 step = (step + 1) >> 1;
1612 }
1613
1614 if (low < maxIndex && lineYOffsetWidget (low + 1, &alloc) <= y)
1615 low++;
1616
1617 /*
1618 * This new routine returns the line number between (top) and
1619 * (top + size.ascent + size.descent + breakSpace): the space
1620 * _below_ the line is considered part of the line. Old routine
1621 * returned line number between (top - previous_line->breakSpace)
1622 * and (top + size.ascent + size.descent): the space _above_ the
1623 * line was considered part of the line. This is important for
1624 * Dw_page_find_link() --EG
1625 * That function has now been inlined into Dw_page_motion_notify() --JV
1626 */
1627
1628 DBG_OBJ_LEAVE_VAL ("%d", low);
1629 return low;
1630}
1631
1635int Textblock::findLineOfWord (int wordIndex)
1636{
1637 if (wordIndex < 0 || wordIndex >= words->size () ||
1638 // Also regard not-yet-existing lines.
1639 lines->size () <= 0 || wordIndex > lines->getLastRef()->lastWord)
1640 return -1;
1641
1642 int high = lines->size () - 1, index, low = 0;
1643
1644 while (true) {
1645 index = (low + high) / 2;
1646 if (wordIndex >= lines->getRef(index)->firstWord) {
1647 if (wordIndex <= lines->getRef(index)->lastWord)
1648 return index;
1649 else
1650 low = index + 1;
1651 } else
1652 high = index - 1;
1653 }
1654}
1655
1660{
1661 int high = paragraphs->size () - 1, index, low = 0;
1662
1663 if (wordIndex < 0 || wordIndex >= words->size () ||
1664 // It may be that the paragraphs list is incomplete. But look
1665 // also at fillParagraphs, where this method is called.
1666 (paragraphs->size () == 0 ||
1667 wordIndex > paragraphs->getLastRef()->lastWord))
1668 return -1;
1669
1670 while (true) {
1671 index = (low + high) / 2;
1672 if (wordIndex >= paragraphs->getRef(index)->firstWord) {
1673 if (wordIndex <= paragraphs->getRef(index)->lastWord)
1674 return index;
1675 else
1676 low = index + 1;
1677 } else
1678 high = index - 1;
1679 }
1680}
1681
1685Textblock::Word *Textblock::findWord (int x, int y, bool *inSpace)
1686{
1687 int lineIndex, wordIndex;
1688 int xCursor, lastXCursor, yWidgetBase;
1689 Line *line;
1690 Word *word;
1691
1692 *inSpace = false;
1693
1694 if ((lineIndex = findLineIndexWhenAllocated (y)) >= lines->size ())
1695 return NULL;
1696 line = lines->getRef (lineIndex);
1697 yWidgetBase = lineYOffsetWidget (line) + line->borderAscent;
1698 if (yWidgetBase + line->borderDescent <= y)
1699 return NULL;
1700
1701 xCursor = line->textOffset;
1702 for (wordIndex = line->firstWord; wordIndex <= line->lastWord;wordIndex++) {
1703 word = words->getRef (wordIndex);
1704 lastXCursor = xCursor;
1705 xCursor += word->size.width + word->effSpace;
1706 if (lastXCursor <= x && xCursor > x) {
1707 if (x >= xCursor - word->effSpace) {
1708 if (wordIndex < line->lastWord &&
1709 (words->getRef(wordIndex + 1)->content.type !=
1711 y > yWidgetBase - word->spaceStyle->font->ascent &&
1712 y <= yWidgetBase + word->spaceStyle->font->descent) {
1713 *inSpace = true;
1714 return word;
1715 }
1716 } else {
1717 if (y > yWidgetBase - word->size.ascent &&
1718 y <= yWidgetBase + word->size.descent)
1719 return word;
1720 }
1721 break;
1722 }
1723 }
1724
1725 return NULL;
1726}
1727
1729 int level, core::DrawingContext *context)
1730{
1731 DBG_OBJ_ENTER ("draw", 0, "Textblock::drawLevel", "(%d, %d, %d * %d), %s",
1732 area->x, area->y, area->width, area->height,
1733 stackingLevelText (level));
1734
1735 switch (level) {
1736 case SL_IN_FLOW:
1737 for (int lineIndex = findLineIndexWhenAllocated (area->y);
1738 lineIndex < lines->size (); lineIndex++) {
1739 Line *line = lines->getRef (lineIndex);
1740 if (lineYOffsetWidget (line) >= area->y + area->height)
1741 break;
1742
1743 DBG_OBJ_MSGF ("draw", 0, "line %d (of %d)", lineIndex, lines->size ());
1744 drawLine (line, view, area, context);
1745 }
1746 break;
1747
1748 case SL_OOF_REF:
1749 // TODO Inefficient. Perhaps store OOF references in seperate
1750 // (much smaller!) list.
1751 for (int oofmIndex = 0; oofmIndex < NUM_OOFM; oofmIndex++) {
1752 for (int wordIndex = 0; wordIndex < words->size (); wordIndex++) {
1753 Word *word = words->getRef (wordIndex);
1756 == oofmIndex &&
1758 word->content.widget->drawInterruption (view, area, context);
1759 }
1760 }
1761 break;
1762
1763 default:
1764 OOFAwareWidget::drawLevel (view, area, level, context);
1765 break;
1766 }
1767
1768 DBG_OBJ_LEAVE ();
1769}
1770
1774Textblock::Word *Textblock::addWord (int width, int ascent, int descent,
1776{
1777 DBG_OBJ_ENTER ("construct.word", 0, "addWord", "%d * (%d + %d), %d, %p",
1778 width, ascent, descent, flags, style);
1779
1780 if (lineBreakWidth == -1) {
1782 DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
1783 }
1784
1785 words->increase ();
1786 DBG_OBJ_SET_NUM ("words.size", words->size ());
1787 int wordNo = words->size () - 1;
1788 initWord (wordNo);
1789 fillWord (wordNo, width, ascent, descent, flags, style);
1790
1791 DBG_OBJ_LEAVE ();
1792 return words->getRef (wordNo);
1793}
1794
1798void Textblock::initWord (int wordNo)
1799{
1800 Word *word = words->getRef (wordNo);
1801
1802 word->style = word->spaceStyle = NULL;
1803 word->wordImgRenderer = NULL;
1804 word->spaceImgRenderer = NULL;
1805}
1806
1807void Textblock::cleanupWord (int wordNo)
1808{
1809 Word *word = words->getRef (wordNo);
1810
1812 delete word->content.widget;
1814 delete word->content.widgetReference;
1817 removeWordImgRenderer (wordNo);
1818 removeSpaceImgRenderer (wordNo);
1819
1820 word->style->unref ();
1821 word->spaceStyle->unref ();
1822}
1823
1825{
1826 Word *word = words->getRef (wordNo);
1827
1828 if (word->style && word->wordImgRenderer) {
1830 (word->wordImgRenderer);
1831 delete word->wordImgRenderer;
1832 word->wordImgRenderer = NULL;
1833 }
1834}
1835
1837{
1838 Word *word = words->getRef (wordNo);
1839
1840 if (word->style->backgroundImage) {
1841 word->wordImgRenderer = new WordImgRenderer (this, wordNo);
1843 (word->wordImgRenderer);
1844 } else
1845 word->wordImgRenderer = NULL;
1846}
1847
1849{
1850 Word *word = words->getRef (wordNo);
1851
1852 if (word->spaceStyle && word->spaceImgRenderer) {
1854 (word->spaceImgRenderer);
1855 delete word->spaceImgRenderer;
1856 word->spaceImgRenderer = NULL;
1857 }
1858}
1859
1861{
1862 Word *word = words->getRef (wordNo);
1863
1864 if (word->spaceStyle->backgroundImage) {
1865 word->spaceImgRenderer = new SpaceImgRenderer (this, wordNo);
1867 (word->spaceImgRenderer);
1868 } else
1869 word->spaceImgRenderer = NULL;
1870}
1871
1872void Textblock::fillWord (int wordNo, int width, int ascent, int descent,
1874{
1875 Word *word = words->getRef (wordNo);
1876
1877 word->size.width = width;
1878 word->size.ascent = ascent;
1879 word->size.descent = descent;
1880 DBG_SET_WORD_SIZE (wordNo);
1881 word->origSpace = word->effSpace = 0;
1882 word->hyphenWidth = 0;
1884 word->content.space = false;
1885 word->flags = flags;
1886
1887 removeWordImgRenderer (wordNo);
1888 removeSpaceImgRenderer (wordNo);
1889
1890 word->style = style;
1891 word->spaceStyle = style;
1892
1893 setWordImgRenderer (wordNo);
1894 setSpaceImgRenderer (wordNo);
1895
1896 style->ref ();
1897 style->ref ();
1898}
1899
1900/*
1901 * Get the width of a string of text.
1902 *
1903 * For "isStart" and "isEnd" see drawText.
1904 */
1905int Textblock::textWidth(const char *text, int start, int len,
1906 core::style::Style *style, bool isStart, bool isEnd)
1907{
1908 int ret = 0;
1909
1910 if (len > 0) {
1911 char *str = NULL;
1912
1913 switch (style->textTransform) {
1915 default:
1916 ret = layout->textWidth(style->font, text+start, len);
1917 break;
1919 str = layout->textToUpper(text+start, len);
1920 ret = layout->textWidth(style->font, str, strlen(str));
1921 break;
1923 str = layout->textToLower(text+start, len);
1924 ret = layout->textWidth(style->font, str, strlen(str));
1925 break;
1927 if (isStart) {
1928 /* \bug No way to know about non-ASCII punctuation. */
1929 bool initial_seen = false;
1930
1931 for (int i = 0; i < start; i++)
1932 if (!ispunct(text[i]))
1933 initial_seen = true;
1934 if (initial_seen) {
1935 ret = layout->textWidth(style->font, text+start, len);
1936 } else {
1937 int after = 0;
1938
1939 text += start;
1940 while (ispunct(text[after]))
1941 after++;
1942 if (text[after])
1943 after = layout->nextGlyph(text, after);
1944 if (after > len)
1945 after = len;
1946 str = layout->textToUpper(text, after);
1947 ret = layout->textWidth(style->font, str, strlen(str)) +
1948 layout->textWidth(style->font, text+after, len-after);
1949 }
1950 } else
1951 ret = layout->textWidth(style->font, text+start, len);
1952 break;
1953 }
1954
1955 if (str)
1956 free(str);
1957 }
1958
1959 return ret;
1960}
1961
1967void Textblock::calcTextSize (const char *text, size_t len,
1969 core::Requisition *size, bool isStart, bool isEnd)
1970{
1971 size->width = textWidth (text, 0, len, style, isStart, isEnd);
1972 size->ascent = style->font->ascent;
1973 size->descent = style->font->descent;
1974
1975 /*
1976 * For 'normal' line height, just use ascent and descent from font.
1977 * For absolute/percentage, line height is relative to font size, which
1978 * is (irritatingly) smaller than ascent+descent.
1979 */
1981 int height, leading;
1982 float factor = style->font->size;
1983
1984 factor /= (style->font->ascent + style->font->descent);
1985
1986 size->ascent = lout::misc::roundInt(size->ascent * factor);
1987 size->descent = lout::misc::roundInt(size->descent * factor);
1988
1989 /* TODO: The containing block's line-height property gives a minimum
1990 * height for the line boxes. (Even when it's set to 'normal', i.e.,
1991 * AUTO? Apparently.) Once all block elements make Textblocks or
1992 * something, this can be handled.
1993 */
1996 else
1997 height =
1999 style->lineHeight);
2000 leading = height - style->font->size;
2001
2002 size->ascent += leading / 2;
2003 size->descent += leading - (leading / 2);
2004 }
2005
2006 /* In case of a sub or super script we increase the word's height and
2007 * potentially the line's height.
2008 */
2010 int requiredDescent = style->font->descent + style->font->ascent / 3;
2011 size->descent = misc::max (size->descent, requiredDescent);
2012 } else if (style->valign == core::style::VALIGN_SUPER) {
2013 int requiredAscent = style->font->ascent + style->font->ascent / 2;
2014 size->ascent = misc::max (size->ascent, requiredAscent);
2015 }
2016}
2017
2022void Textblock::addText (const char *text, size_t len,
2024{
2025 DBG_OBJ_ENTER ("construct.word", 0, "addText", "..., %d, %p",
2026 (int)len, style);
2027
2028 // Count dividing characters.
2029 int numParts = 1;
2030
2031 for (const char *s = text; s; s = nextUtf8Char (s, text + len - s)) {
2032 int foundDiv = -1;
2033 for (int j = 0; foundDiv == -1 && j < NUM_DIV_CHARS; j++) {
2034 int lDiv = strlen (divChars[j].s);
2035 if (s <= text + len - lDiv) {
2036 if (memcmp (s, divChars[j].s, lDiv * sizeof (char)) == 0)
2037 foundDiv = j;
2038 }
2039 }
2040
2041 if (foundDiv != -1) {
2042 if (divChars[foundDiv].penaltyIndexLeft != -1)
2043 numParts ++;
2044 if (divChars[foundDiv].penaltyIndexRight != -1)
2045 numParts ++;
2046 }
2047 }
2048
2049 if (numParts == 1) {
2050 // Simple (and common) case: no dividing characters. May still
2051 // be hyphenated automatically.
2052 core::Requisition size;
2053 calcTextSize (text, len, style, &size, true, true);
2054 addText0 (text, len,
2056 style, &size);
2057
2058 //printf ("[%p] %d: added simple word: ", this, words->size() - 1);
2059 //printWordWithFlags (words->getLastRef());
2060 //printf ("\n");
2061 } else {
2062 PRINTF ("HYPHENATION: '");
2063 for (size_t i = 0; i < len; i++)
2064 PUTCHAR(text[i]);
2065 PRINTF ("', with %d parts\n", numParts);
2066
2067 // Store hyphen positions.
2068 int n = 0, totalLenCharRemoved = 0;
2069 int partPenaltyIndex[numParts - 1];
2070 int partStart[numParts], partEnd[numParts];
2071 bool charRemoved[numParts - 1], canBeHyphenated[numParts + 1];
2072 bool permDivChar[numParts - 1], unbreakableForMinWidth[numParts - 1];
2073 canBeHyphenated[0] = canBeHyphenated[numParts] = true;
2074 partStart[0] = 0;
2075 partEnd[numParts - 1] = len;
2076
2077 for (const char *s = text; s; s = nextUtf8Char (s, text + len - s)) {
2078 int foundDiv = -1;
2079 for (int j = 0; foundDiv == -1 && j < NUM_DIV_CHARS; j++) {
2080 int lDiv = strlen (divChars[j].s);
2081 if (s <= text + len - lDiv) {
2082 if (memcmp (s, divChars[j].s, lDiv * sizeof (char)) == 0)
2083 foundDiv = j;
2084 }
2085 }
2086
2087 if (foundDiv != -1) {
2088 int lDiv = strlen (divChars[foundDiv].s);
2089
2090 if (divChars[foundDiv].charRemoved) {
2091 assert (divChars[foundDiv].penaltyIndexLeft != -1);
2092 assert (divChars[foundDiv].penaltyIndexRight == -1);
2093
2094 partPenaltyIndex[n] = divChars[foundDiv].penaltyIndexLeft;
2095 charRemoved[n] = true;
2096 permDivChar[n] = false;
2097 unbreakableForMinWidth[n] =
2099 canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated;
2100 partEnd[n] = s - text;
2101 partStart[n + 1] = s - text + lDiv;
2102 n++;
2103 totalLenCharRemoved += lDiv;
2104 } else {
2105 assert (divChars[foundDiv].penaltyIndexLeft != -1 ||
2106 divChars[foundDiv].penaltyIndexRight != -1);
2107
2108 if (divChars[foundDiv].penaltyIndexLeft != -1) {
2109 partPenaltyIndex[n] = divChars[foundDiv].penaltyIndexLeft;
2110 charRemoved[n] = false;
2111 permDivChar[n] = false;
2112 unbreakableForMinWidth[n] =
2114 canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated;
2115 partEnd[n] = s - text;
2116 partStart[n + 1] = s - text;
2117 n++;
2118 }
2119
2120 if (divChars[foundDiv].penaltyIndexRight != -1) {
2121 partPenaltyIndex[n] = divChars[foundDiv].penaltyIndexRight;
2122 charRemoved[n] = false;
2123 permDivChar[n] = true;
2124 unbreakableForMinWidth[n] =
2126 canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated;
2127 partEnd[n] = s - text + lDiv;
2128 partStart[n + 1] = s - text + lDiv;
2129 n++;
2130 }
2131 }
2132 }
2133 }
2134
2135 // Get text without removed characters, e. g. hyphens.
2136 const char *textWithoutHyphens;
2137 char textWithoutHyphensBuf[len - totalLenCharRemoved];
2138 int *breakPosWithoutHyphens, breakPosWithoutHyphensBuf[numParts - 1];
2139
2140 if (totalLenCharRemoved == 0) {
2141 // No removed characters: take original arrays.
2142 textWithoutHyphens = text;
2143 // Ends are also break positions, except the last end, which
2144 // is superfluous, but does not harm (since arrays in C/C++
2145 // does not have an implicit length).
2146 breakPosWithoutHyphens = partEnd;
2147 } else {
2148 // Copy into special buffers.
2149 textWithoutHyphens = textWithoutHyphensBuf;
2150 breakPosWithoutHyphens = breakPosWithoutHyphensBuf;
2151
2152 int n = 0;
2153 for (int i = 0; i < numParts; i++) {
2154 memmove (textWithoutHyphensBuf + n, text + partStart[i],
2155 partEnd[i] - partStart[i]);
2156 n += partEnd[i] - partStart[i];
2157 if (i < numParts - 1)
2158 breakPosWithoutHyphensBuf[i] = n;
2159 }
2160 }
2161
2162 PRINTF("H... without hyphens: '");
2163 for (size_t i = 0; i < len - totalLenCharRemoved; i++)
2164 PUTCHAR(textWithoutHyphens[i]);
2165 PRINTF("'\n");
2166
2167 core::Requisition wordSize[numParts];
2168 calcTextSizes (textWithoutHyphens, len - totalLenCharRemoved, style,
2169 numParts - 1, breakPosWithoutHyphens, wordSize);
2170
2171 // Finished!
2172 for (int i = 0; i < numParts; i++) {
2173 short flags = 0;
2174
2175 // If this parts adjoins at least one division characters,
2176 // for which canBeHyphenated is set to false (this is the
2177 // case for soft hyphens), do not hyphenate.
2178 if (canBeHyphenated[i] && canBeHyphenated[i + 1])
2180
2181 if(i < numParts - 1) {
2182 if (charRemoved[i])
2184
2185 if (permDivChar[i])
2187 if (unbreakableForMinWidth[i])
2189
2191 }
2192
2193 if (i == 0)
2195 if (i == numParts - 1)
2197
2198 addText0 (text + partStart[i], partEnd[i] - partStart[i],
2199 flags, style, &wordSize[i]);
2200
2201 //printf ("[%p] %d: added word part: ", this, words->size() - 1);
2202 //printWordWithFlags (words->getLastRef());
2203 //printf ("\n");
2204
2205 //PRINTF("H... [%d] '", i);
2206 //for (int j = partStart[i]; j < partEnd[i]; j++)
2207 // PUTCHAR(text[j]);
2208 //PRINTF("' added\n");
2209
2210 if(i < numParts - 1) {
2211 Word *word = words->getLastRef();
2212
2213 setBreakOption (word, style, penalties[partPenaltyIndex[i]][0],
2214 penalties[partPenaltyIndex[i]][1], false);
2215 DBG_SET_WORD (words->size () - 1);
2216
2217 if (charRemoved[i])
2218 // Currently, only unconditional hyphens (UTF-8:
2219 // "\xe2\x80\x90") can be used. See also drawWord, last
2220 // section "if (drawHyphen)".
2221 // Could be extended by adding respective members to
2222 // DivChar and Word.
2223 word->hyphenWidth =
2225 strlen (hyphenDrawChar));
2226
2227 accumulateWordData (words->size() - 1);
2229 }
2230 }
2231 }
2232
2233 DBG_OBJ_LEAVE ();
2234}
2235
2236void Textblock::calcTextSizes (const char *text, size_t textLen,
2238 int numBreaks, int *breakPos,
2239 core::Requisition *wordSize)
2240{
2241 // The size of the last part is calculated in a simple way.
2242 int lastStart = breakPos[numBreaks - 1];
2243 calcTextSize (text + lastStart, textLen - lastStart, style,
2244 &wordSize[numBreaks], true, true);
2245
2246 PRINTF("H... [%d] '", numBreaks);
2247 for (size_t i = 0; i < textLen - lastStart; i++)
2248 PUTCHAR(text[i + lastStart]);
2249 PRINTF("' -> %d\n", wordSize[numBreaks].width);
2250
2251 // The rest is more complicated. See dw-line-breaking, section
2252 // "Hyphens".
2253 for (int i = numBreaks - 1; i >= 0; i--) {
2254 int start = (i == 0) ? 0 : breakPos[i - 1];
2255 calcTextSize (text + start, textLen - start, style, &wordSize[i],
2256 i == 0, i == numBreaks - 1);
2257
2258 PRINTF("H... [%d] '", i);
2259 for (size_t j = 0; j < textLen - start; j++)
2260 PUTCHAR(text[j + start]);
2261 PRINTF("' -> %d\n", wordSize[i].width);
2262
2263 for (int j = i + 1; j < numBreaks + 1; j++) {
2264 wordSize[i].width -= wordSize[j].width;
2265 PRINTF("H... - %d = %d\n", wordSize[j].width, wordSize[i].width);
2266 }
2267 }
2268}
2269
2274bool Textblock::calcSizeOfWidgetInFlow (int wordIndex, Widget *widget,
2275 core::Requisition *size)
2276{
2277 DBG_OBJ_ENTER ("resize", 0, "calcSizeOfWidgetInFlow", "%d, %p, ...",
2278 wordIndex, widget);
2279
2280 bool result, firstWordOfLine;
2281
2282 if (hasListitemValue)
2283 // For list items, the word #0 at the beginning (bullet, number ...) has
2284 // to be considered;
2285 firstWordOfLine = wordIndex == 1 ||
2286 (wordIndex > 0 &&
2287 words->getRef(wordIndex - 1)->content.type == core::Content::BREAK);
2288 else
2289 firstWordOfLine = wordIndex == 0 ||
2290 words->getRef(wordIndex - 1)->content.type == core::Content::BREAK;
2291
2292 DBG_OBJ_MSGF ("resize", 1, "firstWordOfLine = %s",
2293 boolToStr (firstWordOfLine));
2294
2295 if (firstWordOfLine &&
2296 (widget->getStyle()->display == core::style::DISPLAY_BLOCK ||
2297 widget->getStyle()->display == core::style::DISPLAY_LIST_ITEM ||
2298 widget->getStyle()->display == core::style::DISPLAY_TABLE)) {
2299 // pass positions
2300 DBG_OBJ_MSG ("resize", 1, "pass position");
2301 int lastWord = lines->empty () ? -1 : lines->getLastRef()->lastWord;
2302 assert (wordIndex > lastWord);
2303
2304 // The position passed to sizeRequest must be equivalent to the position
2305 // passed later to sizeAllocate. This is more complicated for widgets
2306 // which are centered or aligned to the right: here, we have to know the
2307 // width to calculate the horizontal position. Both are calculated in an
2308 // iterative way; initially, the left border is used (like for other,
2309 // simpler alignments).
2310
2311 // Since the child widget will regard floats, we do not have to include
2312 // floats when calculating left and right border.
2313
2314 // TODO Actually line1OffsetEff should be used instead of line1Offset, but
2315 // it may not initialized here. Anyway, since ignoreLine1OffsetSometimes
2316 // is not used, line1OffsetEff is always equal to line1Offset.
2317
2318 int leftBorder = boxOffsetX () + leftInnerPadding
2319 + (lines->size () == 0 ? line1Offset /* ...Eff, actually */ : 0);
2320 int rightBorder = boxRestWidth ();
2321
2322 int lastMargin, yLine = yOffsetOfLineToBeCreated (&lastMargin);
2323 int yRel = yLine - min (lastMargin, widget->getStyle()->margin.top);
2324
2325 DBG_OBJ_MSGF ("resize", 1,
2326 "leftBorder = %d + %d + (%d == 0 ? %d : 0) = %d, "
2327 "rightBorder = %d, yRel = %d - min (%d, %d) = %d",
2328 boxOffsetX (), leftInnerPadding , lines->size (),
2329 line1OffsetEff, leftBorder, rightBorder, yLine, lastMargin,
2330 widget->getStyle()->margin.top, yRel);
2331
2332 core::SizeParams childParams;
2333 DBG_OBJ_ASSOC_CHILD (&childParams);
2334
2335 int oldXRel = leftBorder;
2336
2337 sizeRequestParams.forChild (this, widget, oldXRel, yRel, &childParams);
2338 widget->sizeRequest (size, childParams.getNumPos (),
2339 childParams.getReferences (), childParams.getX (),
2340 childParams.getY ());
2341
2343
2344 while (true) {
2346
2347 int xRel;
2348
2349 switch(widget->getStyle()->textAlign) {
2351 case core::style::TEXT_ALIGN_STRING: // see comment in alignLine()
2352 case core::style::TEXT_ALIGN_JUSTIFY: // equivalent for only one word
2353 default: // compiler happiness
2354 xRel = leftBorder;
2355 break;
2356
2358 xRel = lineBreakWidth - rightBorder - size->width;
2359 break;
2360
2362 xRel =
2363 (leftBorder + lineBreakWidth - rightBorder - size->width) / 2;
2364 break;
2365 }
2366
2367 // Cf. Textblock::calcTextOffset().
2368 if (xRel < leftBorder)
2369 xRel = leftBorder;
2370
2371 DBG_OBJ_MSGF ("resize", 2, "xRel = %d, oldXRel = %d", xRel, oldXRel);
2372
2373 // Stop when the value of xRel has not changed during the last
2374 // iteration.
2375 if (xRel == oldXRel)
2376 break;
2377
2378 sizeRequestParams.forChild (this, widget, xRel, yRel, &childParams);
2379 widget->sizeRequest (size, childParams.getNumPos (),
2380 childParams.getReferences (), childParams.getX (),
2381 childParams.getY ());
2382
2383 oldXRel = xRel;
2384
2385 DBG_OBJ_MSG_END ();
2386 }
2387
2388 DBG_OBJ_MSG_END ();
2389
2390 result = true;
2391 } else {
2392 // do not pass positions (inline elements etc)
2393 DBG_OBJ_MSG ("resize", 1, "do not pass position");
2394 widget->sizeRequest (size);
2395 result = false;
2396 }
2397
2398 DBG_OBJ_LEAVE_VAL ("%s", boolToStr (result));
2399 return result;
2400}
2401
2403 int *yRef)
2404{
2405 if (reference == this) {
2406 if (xRef)
2407 *xRef = 0;
2408 if (yRef)
2409 *yRef = 0;
2410 return true;
2411 } else
2412 return sizeRequestParams.findReference (reference, xRef, yRef);
2413}
2414
2418void Textblock::addText0 (const char *text, size_t len, short flags,
2420{
2421 DBG_OBJ_ENTER ("construct.word", 0, "addText0",
2422 "..., %d, %s:%s:%s:%s:%s:%s:%s:%s, %p, %d * (%d + %d)",
2423 (int)len,
2424 (flags & Word::CAN_BE_HYPHENATED) ? "h?" : "--",
2425 (flags & Word::DIV_CHAR_AT_EOL) ? "de" : "--",
2426 (flags & Word::PERM_DIV_CHAR) ? "dp" : "--",
2427 (flags & Word::DRAW_AS_ONE_TEXT) ? "t1" : "--",
2428 (flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) ? "um" : "--",
2429 (flags & Word::WORD_START) ? "st" : "--",
2430 (flags & Word::WORD_END) ? "en" : "--",
2431 (flags & Word::TOPLEFT_OF_LINE) ? "00" : "--",
2432 style, size->width, size->ascent, size->descent);
2433
2434 //printf("[%p] addText0 ('", this);
2435 //for (size_t i = 0; i < len; i++)
2436 // putchar(text[i]);
2437 //printf("', ");
2438 //printWordFlags (flags);
2439 //printf (", ...)\n");
2440
2441 Word *word = addWord (size->width, size->ascent, size->descent,
2442 flags, style);
2444 word->content.type = core::Content::TEXT;
2445 word->content.text = layout->textZone->strndup(text, len);
2446
2447 DBG_SET_WORD (words->size () - 1);
2448
2449 // The following debug message may be useful to identify the
2450 // different textblocks.
2451
2452 //if (words->size() == 1)
2453 // printf ("[%p] first word: '%s'\n", this, text);
2454
2455 processWord (words->size () - 1);
2456
2457 DBG_OBJ_LEAVE ();
2458}
2459
2464{
2465 DBG_OBJ_ENTER ("construct.word", 0, "addWidget", "%p, %p", widget, style);
2466
2467 /* We first assign -1 as parent_ref, since the call of widget->size_request
2468 * will otherwise let this Textblock be rewrapped from the beginning.
2469 * (parent_ref is actually undefined, but likely has the value 0.) At the,
2470 * end of this function, the correct value is assigned. */
2471 widget->parentRef = -1;
2472 DBG_OBJ_SET_NUM_O (widget, "parentRef", widget->parentRef);
2473
2474 widget->setStyle (style);
2475
2477
2478 if (testWidgetOutOfFlow (widget)) {
2479 int oofmIndex = getOOFMIndex (widget);
2480 DBG_OBJ_MSGF ("construct.word", 1, "ouf of flow: oofmIndex = %d (%s)",
2481 oofmIndex, OOFM_NAME[oofmIndex]);
2482
2483 widget->setParent (oofContainer[oofmIndex]);
2484 widget->setGenerator (this);
2485
2486 oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr (oofmIndex);
2487 int oofmSubRef = oofm->addWidgetOOF (widget, this, words->size ());
2488 widget->parentRef = makeParentRefOOF (oofmIndex, oofmSubRef);
2489
2490 DBG_OBJ_MSGF ("construct.word", 1, "oofmSubRef = %d => parentRef = %d",
2491 oofmSubRef, widget->parentRef);
2492
2493 core::Requisition size;
2494 oofm->calcWidgetRefSize (widget, &size);
2495 Word *word = addWord (size.width, size.ascent, size.descent, 0, style);
2497 word->content.widgetReference = new core::WidgetReference (widget);
2499
2500 // After a out-of-flow reference, breaking is allowed. (This avoids some
2501 // problems with breaking near float definitions.)
2502 setBreakOption (word, style, 0, 0, false);
2503 } else {
2504 DBG_OBJ_MSG ("construct.word", 1, "in flow");
2505
2506 widget->setParent (this);
2507
2508 // TODO Replace (perhaps) later "textblock" by "OOF aware widget".
2509 if (widget->instanceOf (Textblock::CLASS_ID)) {
2510 for (int i = 0; i < NUM_OOFM; i++)
2511 searchOutOfFlowMgr(i)->addWidgetInFlow ((Textblock*)widget, this,
2512 words->size ());
2513 }
2514
2515 core::Requisition size;
2516 short flags = calcSizeOfWidgetInFlow (words->size (), widget, &size) ?
2518 Word *word =
2519 addWord (size.width, size.ascent, size.descent, flags, style);
2521 word->content.widget = widget;
2522 }
2523
2524 DBG_SET_WORD (words->size () - 1);
2525
2526 processWord (words->size () - 1);
2527 //DBG_OBJ_SET_NUM (word->content.widget, "parent_ref",
2528 // word->content.widget->parent_ref);
2529
2530 //DEBUG_MSG(DEBUG_REWRAP_LEVEL,
2531 // "Assigning parent_ref = %d to added word %d, "
2532 // "in page with %d word(s)\n",
2533 // lines->size () - 1, words->size() - 1, words->size());
2534
2535 DBG_OBJ_LEAVE ();
2536}
2537
2546{
2547 DBG_OBJ_ENTER ("construct.word", 0, "addAnchor", "\"%s\", %p", name, style);
2548
2549 char *copy;
2550 int y;
2551 bool result;
2552
2553 // Since an anchor does not take any space, it is safe to call
2554 // addAnchor already here.
2555 if (wasAllocated ()) {
2556 if (lines->size () == 0)
2557 y = allocation.y;
2558 else
2559 y = allocation.y + lineYOffsetWidget (lines->size () - 1);
2560 copy = Widget::addAnchor (name, y);
2561 } else
2562 copy = Widget::addAnchor (name);
2563
2564 if (copy == NULL)
2569 result = false;
2570 else {
2571 Anchor *anchor;
2572
2573 anchors->increase();
2574 anchor = anchors->getRef(anchors->size() - 1);
2575 anchor->name = copy;
2576 anchor->wordIndex = words->size();
2577 result = true;
2578 }
2579
2580 DBG_OBJ_LEAVE_VAL ("%s", boolToStr(result));
2581 return result;
2582}
2583
2584
2589{
2590 DBG_OBJ_ENTER ("construct.word", 0, "addSpace", "%p", style);
2591
2592 int wordIndex = words->size () - 1;
2593 if (wordIndex >= 0) {
2594 fillSpace (wordIndex, style);
2595 DBG_SET_WORD (wordIndex);
2596 accumulateWordData (wordIndex);
2598 }
2599
2600 DBG_OBJ_LEAVE ();
2601}
2602
2610{
2611 DBG_OBJ_ENTER ("construct.word", 0, "addBreakOption", "%p, %s",
2612 style, forceBreak ? "true" : "false");
2613
2614 int wordIndex = words->size () - 1;
2615 if (wordIndex >= 0) {
2616 setBreakOption (words->getRef(wordIndex), style, 0, 0, forceBreak);
2617 DBG_SET_WORD (wordIndex);
2618 // Call of accumulateWordData() is not needed here.
2620 }
2621
2622 DBG_OBJ_LEAVE ();
2623}
2624
2626{
2627 DBG_OBJ_ENTER ("construct.word", 0, "fillSpace", "%d, ...", wordNo);
2628
2629 DBG_OBJ_MSGF ("construct.word", 1, "style.white-space = %s",
2633 "nowrap"
2635 "pre-wrap"
2637 "pre-line" : "???");
2638
2639 // Old comment:
2640 //
2641 // According to
2642 // http://www.w3.org/TR/CSS2/text.html#white-space-model: "line
2643 // breaking opportunities are determined based on the text
2644 // prior to the white space collapsing steps".
2645 //
2646 // So we call addBreakOption () for each Textblock::addSpace ()
2647 // call. This is important e.g. to be able to break between
2648 // foo and bar in: <span style="white-space:nowrap">foo </span>
2649 // bar
2650 //
2651 // TODO: Re-evaluate again.
2652
2653 Word *word = words->getRef (wordNo);
2654
2655 // TODO: This line does not work: addBreakOption (word, style);
2656
2657 if (// Do not override a previously set break penalty:
2658 !word->content.space &&
2659 // OOF references are considered specially, and must not have a space:
2660 word->content.type != core::Content::WIDGET_OOF_REF) {
2661 setBreakOption (word, style, 0, 0, false);
2662
2663 word->content.space = true;
2664 word->origSpace = word->effSpace =
2666
2667 removeSpaceImgRenderer (wordNo);
2668
2669 word->spaceStyle->unref ();
2670 word->spaceStyle = style;
2671 style->ref ();
2672
2673 setSpaceImgRenderer (wordNo);
2674 }
2675
2676 DBG_OBJ_LEAVE ();
2677}
2678
2685 int breakPenalty1, int breakPenalty2,
2686 bool forceBreak)
2687{
2688 DBG_OBJ_ENTER ("construct.word", 0, "setBreakOption", "..., %d, %d, %s",
2689 breakPenalty1, breakPenalty2, forceBreak ? "true" : "false");
2690
2691 // TODO: lineMustBeBroken should be independent of the penalty
2692 // index? Otherwise, examine the last line.
2693 if (!word->badnessAndPenalty.lineMustBeBroken(0)) {
2694 if (forceBreak || isBreakAllowed (style))
2695 word->badnessAndPenalty.setPenalties (breakPenalty1, breakPenalty2);
2696 else
2698 }
2699
2700 DBG_OBJ_LEAVE ();
2701}
2702
2704{
2705 switch (style->whiteSpace) {
2709 return true;
2710
2713 return false;
2714
2715 default:
2716 // compiler happiness
2718 return false;
2719 }
2720}
2721
2722
2727{
2728 DBG_OBJ_ENTER ("construct.word", 0, "addParbreak", "%d, %p",
2729 space, style);
2730 DBG_OBJ_MSG ("construct.word", 0,
2731 "<i>No nesting! Strack trace may be incomplete.</i>");
2732 DBG_OBJ_LEAVE ();
2733
2734 Word *word;
2735
2736 /* A break may not be the first word of a page, or directly after
2737 the bullet/number (which is the first word) in a list item. (See
2738 also comment in sizeRequest.) */
2739 if (words->size () == 0 ||
2740 (hasListitemValue && words->size () == 1)) {
2741 /* This is a bit hackish: If a break is added as the
2742 first/second word of a page, and the parent widget is also a
2743 Textblock, and there is a break before -- this is the case when
2744 a widget is used as a text box (lists, blockquotes, list
2745 items etc) -- then we simply adjust the break before, in a
2746 way that the space is in any case visible. */
2747 /* Find the widget where to adjust the breakSpace. (Only
2748 consider normal flow, no floats etc.) */
2749 for (Widget *widget = this;
2750 widget->getParent() != NULL &&
2751 widget->getParent()->instanceOf (Textblock::CLASS_ID) &&
2752 !isWidgetOOF (widget);
2753 widget = widget->getParent ()) {
2754 Textblock *textblock2 = (Textblock*)widget->getParent ();
2755 int index = textblock2->hasListitemValue ? 1 : 0;
2756 bool isfirst = (textblock2->words->getRef(index)->content.type
2758 && textblock2->words->getRef(index)->content.widget
2759 == widget);
2760 if (!isfirst) {
2761 /* The text block we searched for has been found. */
2762 Word *word2;
2763 int lineno = getWidgetInFlowSubRef (widget);
2764
2765 if (lineno > 0 &&
2766 (word2 =
2767 textblock2->words->getRef(textblock2->lines
2768 ->getRef(lineno - 1)->firstWord)) &&
2769 word2->content.type == core::Content::BREAK) {
2770 if (word2->content.breakSpace < space) {
2771 word2->content.breakSpace = space;
2772 textblock2->queueResize (makeParentRefInFlow (lineno), false);
2773 textblock2->mustQueueResize = false;
2774 DBG_OBJ_SET_BOOL_O (textblock2, "mustQueueResize",
2775 textblock2->mustQueueResize);
2776 }
2777 }
2778 return;
2779 }
2780 /* Otherwise continue to examine parents. */
2781 }
2782
2783 /* Return in any case. */
2784 return;
2785 }
2786
2787 /* Another break before? */
2788 if ((word = words->getRef(words->size () - 1)) &&
2790 Line *lastLine = lines->getRef (lines->size () - 1);
2791
2792 word->content.breakSpace =
2793 misc::max (word->content.breakSpace, space);
2794 lastLine->breakSpace =
2796 lastLine->marginDescent - lastLine->borderDescent,
2797 lastLine->breakSpace);
2798 return;
2799 }
2800
2801 word = addWord (0, 0, 0, 0, style);
2805 word->content.breakSpace = space;
2806
2807 DBG_SET_WORD (words->size () - 1);
2808
2809 breakAdded ();
2810 processWord (words->size () - 1);
2811}
2812
2813/*
2814 * Cause a line break.
2815 */
2817{
2818 DBG_OBJ_ENTER ("construct.word", 0, "addLinebreak", "%p", style);
2819
2820 Word *word;
2821
2822 if (words->size () == 0 ||
2823 words->getRef(words->size () - 1)->content.type == core::Content::BREAK)
2824 // An <BR> in an empty line gets the height of the current font
2825 // (why would someone else place it here?), ...
2826 word =
2828 else
2829 // ... otherwise, it has no size (and does not enlarge the line).
2830 word = addWord (0, 0, 0, 0, style);
2831
2833
2836 word->content.breakSpace = 0;
2837
2838 DBG_SET_WORD (words->size () - 1);
2839
2840 breakAdded ();
2841 processWord (words->size () - 1);
2842
2843 DBG_OBJ_LEAVE ();
2844}
2845
2850{
2851 assert (words->size () >= 1);
2852 assert (words->getRef(words->size () - 1)->content.type
2854
2855 // Any space before is removed. It is not used; on the other hand,
2856 // this snippet (an example from a real-world debugging session)
2857 // would cause problems:
2858 //
2859 // <input style="width: 100%" .../>
2860 // <button ...>...</button>
2861 //
2862 // (Notice the space between <input> and <button>, and also that
2863 // the HTML parser will insert a BREAK between them.) The <input>
2864 // would be given the available width ("width: 100%"), but the
2865 // actual width (Word::totalWidth) would include the space, so that
2866 // the width of the line is larger than the available width.
2867
2868 if (words->size () >= 2)
2869 words->getRef(words->size () - 2)->origSpace =
2870 words->getRef(words->size () - 2)->effSpace = 0;
2871}
2872
2875 *context)
2876{
2877 DBG_OBJ_ENTER ("events", 0, "Textblock::getWidgetAtPointLevel", "%d, %d, %s",
2878 x, y, stackingLevelText (level));
2879
2880 Widget *widgetAtPoint = NULL;
2881
2882 switch (level) {
2883 case SL_IN_FLOW:
2884 {
2885 int lineIndex = findLineIndexWhenAllocated (y - allocation.y);
2886
2887 if (lineIndex >= 0 && lineIndex < lines->size ()) {
2888 Line *line = lines->getRef (lineIndex);
2889
2890 for (int wordIndex = line->lastWord;
2891 widgetAtPoint == NULL && wordIndex >= line->firstWord;
2892 wordIndex--) {
2893 Word *word = words->getRef (wordIndex);
2896 (word->content.widget))
2897 widgetAtPoint =
2898 word->content.widget->getWidgetAtPoint (x, y, context);
2899 }
2900 }
2901 }
2902 break;
2903
2904 case SL_OOF_REF:
2905 // TODO Inefficient. Perhaps store OOF references in seperate
2906 // (much smaller!) list.
2907 for (int oofmIndex = NUM_OOFM; widgetAtPoint == NULL && oofmIndex >= 0;
2908 oofmIndex--) {
2909 for (int wordIndex = words->size () - 1;
2910 widgetAtPoint == NULL && wordIndex >= 0; wordIndex--) {
2911 Word *word = words->getRef (wordIndex);
2914 == oofmIndex &&
2916 ->widget))
2917 widgetAtPoint =
2919 ->getWidgetAtPointInterrupted (x, y, context);
2920 }
2921 }
2922 break;
2923
2924 default:
2925 widgetAtPoint =
2926 OOFAwareWidget::getWidgetAtPointLevel (x, y, level, context);
2927 break;
2928 }
2929
2930 DBG_OBJ_LEAVE_VAL ("%p", widgetAtPoint);
2931 return widgetAtPoint;
2932}
2933
2939{
2940 if (lines->size() > 0) {
2941 Widget *parent;
2942 Line *lastLine = lines->getRef (lines->size () - 1);
2943
2944 if (lastLine->breakSpace != 0 && (parent = getParent()) &&
2947 Textblock *textblock2 = (Textblock*) parent;
2948 textblock2->addParbreak(lastLine->breakSpace, style);
2949 }
2950 }
2951}
2952
2953/*
2954 * Any words added by addWord() are not immediately (queued to
2955 * be) drawn, instead, this function must be called. This saves some
2956 * calls to queueResize().
2957 *
2958 */
2960{
2961 DBG_OBJ_ENTER0 ("resize", 0, "flush");
2962
2963 if (mustQueueResize) {
2964 DBG_OBJ_MSG ("resize", 0, "mustQueueResize set");
2965
2966 queueResize (-1, true);
2967 mustQueueResize = false;
2968 DBG_OBJ_SET_BOOL ("mustQueueResize", mustQueueResize);
2969 }
2970
2971 DBG_OBJ_LEAVE ();
2972}
2973
2974
2975// next: Dw_page_find_word
2976
2977void Textblock::changeLinkColor (int link, int newColor)
2978{
2979 for (int lineIndex = 0; lineIndex < lines->size(); lineIndex++) {
2980 bool changed = false;
2981 Line *line = lines->getRef (lineIndex);
2982 int wordIdx;
2983
2984 for (wordIdx = line->firstWord; wordIdx <= line->lastWord; wordIdx++){
2985 Word *word = words->getRef(wordIdx);
2986
2987 if (word->style->x_link == link) {
2988 core::style::StyleAttrs styleAttrs;
2989
2990 switch (word->content.type) {
2992 { core::style::Style *old_style = word->style;
2993 styleAttrs = *old_style;
2995 newColor);
2996 word->style = core::style::Style::create (&styleAttrs);
2997 old_style->unref();
2998 old_style = word->spaceStyle;
2999 styleAttrs = *old_style;
3001 newColor);
3002 word->spaceStyle = core::style::Style::create(&styleAttrs);
3003 old_style->unref();
3004 break;
3005 }
3007 { core::Widget *widget = word->content.widget;
3008 styleAttrs = *widget->getStyle();
3010 newColor);
3011 styleAttrs.setBorderColor(
3013 widget->setStyle(core::style::Style::create (&styleAttrs));
3014 break;
3015 }
3016 default:
3017 break;
3018 }
3019 changed = true;
3020 }
3021 }
3022 if (changed)
3024 line->borderAscent + line->borderDescent);
3025 }
3026}
3027
3029 bool includeFirstSpace, bool includeLastSpace)
3030{
3031}
3032
3033void Textblock::queueDrawRange (int index1, int index2)
3034{
3035 DBG_OBJ_ENTER ("draw", 0, "queueDrawRange", "%d, %d", index1, index2);
3036
3037 int from = misc::min (index1, index2);
3038 int to = misc::max (index1, index2);
3039
3040 from = misc::min (from, words->size () - 1);
3041 from = misc::max (from, 0);
3042 to = misc::min (to, words->size () - 1);
3043 to = misc::max (to, 0);
3044
3045 int line1idx = findLineOfWord (from);
3046 int line2idx = findLineOfWord (to);
3047
3048 if (line1idx >= 0 && line2idx >= 0) {
3049 Line *line1 = lines->getRef (line1idx),
3050 *line2 = lines->getRef (line2idx);
3051 int y = lineYOffsetWidget (line1) + line1->borderAscent -
3052 line1->contentAscent;
3053 int h = lineYOffsetWidget (line2) + line2->borderAscent +
3054 line2->contentDescent - y;
3055
3056 queueDrawArea (0, y, allocation.width, h);
3057 }
3058
3059 DBG_OBJ_LEAVE ();
3060}
3061
3063{
3064 DBG_OBJ_ENTER ("resize", 0, "updateReference", "%d", ref);
3065
3066 // Only `queueResize` when there're words or float clearance
3067 // (float clearance may change `extraSpace.top`).
3068 if (words->size () > 0 || getStyle()->clear != core::style::CLEAR_NONE)
3069 queueResize (ref, false);
3070
3071 DBG_OBJ_LEAVE ();
3072}
3073
3074void Textblock::widgetRefSizeChanged (int externalIndex)
3075{
3076 int lineNo = findLineOfWord (externalIndex);
3077 if (lineNo >= 0 && lineNo < lines->size ())
3078 queueResize (makeParentRefInFlow (lineNo), true);
3079}
3080
3082{
3083 DBG_OBJ_ENTER ("resize", 0, "oofSizeChanged", "%s",
3084 extremesChanged ? "true" : "false");
3086
3087 // See Textblock::getAvailWidthOfChild(): Extremes changes may become also
3088 // relevant for the children, under certain conditions:
3091
3092 DBG_OBJ_LEAVE ();
3093}
3094
3095int Textblock::getGeneratorX (int oofmIndex)
3096{
3097 DBG_OBJ_ENTER ("resize", 0, "Textblock::getGeneratorX", "%d", oofmIndex);
3098
3099 int x, xRef;
3100 if (findSizeRequestReference (oofmIndex, &xRef, NULL))
3101 x = xRef;
3102 else {
3103 // Only called for floats, so this should not happen:
3105 x = 0;
3106 }
3107
3108 DBG_OBJ_LEAVE_VAL ("%d", x);
3109 return x;
3110}
3111
3112int Textblock::getGeneratorY (int oofmIndex)
3113{
3114 DBG_OBJ_ENTER ("resize", 0, "Textblock::getGeneratorY", "%d", oofmIndex);
3115
3116 int yRef, y;
3117 if (findSizeRequestReference (oofmIndex, NULL, &yRef))
3118 y = yRef;
3119 else {
3120 // Only called for floats, so this should not happen:
3122 y = 0;
3123 }
3124
3125 DBG_OBJ_LEAVE_VAL ("%d", y);
3126 return y;
3127}
3128
3130{
3131 DBG_OBJ_ENTER ("resize", 0, "Textblock::getGeneratorRest", "%d", oofmIndex);
3132
3133 int xRef, rest;
3135
3136 if (container != NULL && findSizeRequestReference (container, &xRef, NULL))
3137 rest = container->getGeneratorWidth () - (xRef + getGeneratorWidth ());
3138 else {
3139 // Only callend for floats, so this should not happen:
3141 rest = 0;
3142 }
3143
3144 DBG_OBJ_LEAVE_VAL ("%d", rest);
3145 return rest;
3146}
3147
3149{
3150 DBG_OBJ_ENTER0 ("resize", 0, "Textblock::getGeneratorWidth");
3151
3152 // Cf. sizeRequestImpl.
3153 if (usesMaxGeneratorWidth ()) {
3155 return lineBreakWidth;
3156 } else {
3157 // In some cases (especially when called from sizeRequest for an
3158 // ancestor), the value is not up to date, since content from children is
3159 // not yet added to lines. Moreover, this leads to inconsistencies between
3160 // this widget and ancestors (as in Textblock::getGeneratorRest). For this
3161 // reason, the children are examined recursively.
3162 //
3163 // Test case:
3164 //
3165 // <div style="float:left">
3166 // <div div style="float:right">float</div>
3167 // <div>abcdefghijkl mnopqrstuvwx</div>
3168 // </div>
3169
3170 int wChild = 0;
3171 int firstWordAfterLastLine =
3172 lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0;
3173 for (int i = firstWordAfterLastLine; i < words->size(); i++) {
3174 Word *word = words->getRef(i);
3175 int xRel;
3176 // We only examine instances of dw::Textblock, since they are relevant
3177 // for floats, for which this method is only called.
3180 Textblock *tbChild = (Textblock*)word->content.widget;
3181 if(tbChild->findSizeRequestReference(this, &xRel, NULL))
3182 wChild = max(wChild, xRel + tbChild->getGeneratorWidth());
3183 }
3184 }
3185
3186 DBG_OBJ_MSGF ("resize", 1, "wChild = %d", wChild);
3187
3188 int w0 = lines->size () > 0 ? lines->getLastRef()->maxLineWidth : 0;
3189 DBG_OBJ_MSGF ("resize", 1, "w0 = %d", w0);
3190 int wThis = min(w0 + leftInnerPadding + boxDiffWidth (), lineBreakWidth);
3191 DBG_OBJ_MSGF ("resize", 1, "wThis = min(%d + %d + %d, %d) = %d",
3193 wThis);
3194 int w = max(wThis, wChild);
3195 DBG_OBJ_LEAVE_VAL ("max(%d, %d) = %d", wThis, wChild, w);
3196 return w;
3197 }
3198}
3199
3201{
3202 DBG_OBJ_ENTER0 ("resize", 0, "Textblock::getMaxGeneratorWidth");
3204 return lineBreakWidth;
3205}
3206
3208{
3209 DBG_OBJ_ENTER0 ("resize", 0, "usesMaxGeneratorWidth");
3210
3211 bool result;
3212 if (treatAsInline) {
3213 DBG_OBJ_MSG ("resize", 1, "treatAsInline set");
3214 result = false;
3215 } else {
3216 bool toplevel = getParent () == NULL,
3218 vloat = testWidgetFloat (this),
3219 abspos = testWidgetAbsolutelyPositioned (this),
3220 fixpos = testWidgetFixedlyPositioned (this);
3221 DBG_OBJ_MSGF("resize", 1,
3222 "toplevel: %s, block: %s, float: %s, abspos: %s, fixpos: %s",
3223 boolToStr(toplevel), boolToStr(block), boolToStr(vloat),
3224 boolToStr(abspos), boolToStr(fixpos));
3225
3226 // In detail, this depends on what the respective OOFM does with the
3227 // child widget:
3228 result = toplevel || (block && !(vloat || abspos || fixpos));
3229 }
3230
3231 DBG_OBJ_LEAVE_VAL ("%s", boolToStr(result));
3232 return result;
3233}
3234
3236{
3237 return true;
3238}
3239
3241{
3242 return true;
3243}
3244
3249
3251{
3252 // Can also be used for a line not yet existing.
3253 int firstWord = lineNo == 0 ? 0 : lines->getRef(lineNo - 1)->lastWord + 1;
3254 int lastWord = lineNo < lines->size() ?
3255 lines->getRef(lineNo)->lastWord : words->size() - 1;
3256 return getWidgetRegardingBorderForLine (firstWord, lastWord);
3257}
3258
3260 int lastWord)
3261{
3262 DBG_OBJ_ENTER ("resize", 0, "getWidgetRegardingBorderForLine", "%d, %d",
3263 firstWord, lastWord);
3264 DBG_OBJ_MSGF ("resize", 1, "words.size = %d", words->size ());
3265
3266 RegardingBorder *widgetRegardingBorder = NULL;
3267
3268 if (firstWord < words->size ()) {
3269 // Any instance of a subclass of WidgetRegardingBorder is always
3270 // between two line breaks, and so the first word of the line.
3271 Word *word = words->getRef (firstWord);
3272
3273 DBG_MSG_WORD ("resize", 1, "<i>first word:</i> ", firstWord, "");
3274
3276 Widget *widget = word->content.widget;
3277 if (widget->instanceOf (RegardingBorder::CLASS_ID) &&
3278 // Exclude cases where a textblock constitutes a new floats
3279 // container.
3280 !isOOFContainer (widget, OOFM_FLOATS))
3281 widgetRegardingBorder = (RegardingBorder*)widget;
3282 }
3283 }
3284
3285 DBG_OBJ_LEAVE_VAL ("%p", widgetRegardingBorder);
3286 return widgetRegardingBorder;
3287}
3288
3293{
3294 // This method does not return an exact result: the position of the
3295 // new line, which does not yet exist, cannot be calculated, since
3296 // the top margin of the new line (which collapses either with the
3297 // top margin of the textblock widget, or the bottom margin of the
3298 // last line) must be taken into account. However, this method is
3299 // only called for positioning floats; here, a slight incorrectness
3300 // does not cause real harm.
3301
3302 // (Similar applies to the line *height*, which calculated in an
3303 // iterative way; see wrapWordInFlow. Using the same approach for
3304 // the *position* is possible, but not worth the increased
3305 // complexity.)
3306
3307 DBG_OBJ_ENTER0 ("line.yoffset", 0, "yOffsetOfLineToBeCreated");
3308
3309 int result;
3310
3311 if (lines->size () == 0) {
3312 result = calcVerticalBorder (getStyle()->padding.top,
3313 getStyle()->borderWidth.top + extraSpace.top,
3314 getStyle()->margin.top, 0, 0);
3315 if (lastMargin)
3316 *lastMargin = getStyle()->margin.top;
3317 } else {
3318 Line *firstLine = lines->getRef (0), *lastLine = lines->getLastRef ();
3319 result = calcVerticalBorder (getStyle()->padding.top,
3320 getStyle()->borderWidth.top,
3321 getStyle()->margin.top + extraSpace.top,
3322 firstLine->borderAscent,
3323 firstLine->marginAscent)
3324 - firstLine->borderAscent + lastLine->top + lastLine->totalHeight (0);
3325 if (lastMargin)
3326 *lastMargin = lastLine->marginDescent - lastLine->borderDescent;
3327 }
3328
3329 if (lastMargin)
3330 DBG_OBJ_LEAVE_VAL ("%d, %d", result, *lastMargin);
3331 else
3332 DBG_OBJ_LEAVE_VAL ("%d", result);
3333
3334 return result;
3335}
3336
3341{
3342 // Similar applies (regarding exactness) as to yOffsetOfLineToBeCreated.
3343
3344 DBG_OBJ_ENTER0 ("line.yoffset", 0, "yOffsetOfLineToBeCreated");
3345
3346 int result;
3347
3348 Line *firstLine = lines->getRef (0);
3349 result = calcVerticalBorder (getStyle()->padding.top,
3350 getStyle()->borderWidth.top,
3351 getStyle()->margin.top + extraSpace.top,
3352 firstLine->borderAscent,
3353 firstLine->marginAscent)
3354 - firstLine->borderAscent + line->top;
3355
3356 DBG_OBJ_LEAVE_VAL ("%d", result);
3357 return result;
3358}
3359
3360} // namespace dw
#define _MSG(...)
Definition bookmarks.c:45
Base class (rather a tag interface) for those widgets regarding borders defined by floats,...
void setPenalties(int penalty1, int penalty2)
Sets the penalty, multiplied by 100.
void getBgArea(int *x, int *y, int *width, int *height)
Return the area covered by the background image.
Definition textblock.cc:110
core::style::Style * getStyle()
Return the style this background image is part of.
Definition textblock.cc:118
static TextblockIterator * createWordIndexIterator(Textblock *textblock, core::Content::Type mask, int wordIndex)
Implementation used for words.
Definition textblock.hh:305
bool readyToDraw()
If this method returns false, nothing is done at all.
Definition textblock.cc:70
void draw(int x, int y, int width, int height)
Draw (or queue for drawing) an area, which is given in canvas coordinates.
Definition textblock.cc:103
void setData(int xWordWidget, int lineNo)
Definition textblock.cc:63
WordImgRenderer(Textblock *textblock, int wordNo)
Definition textblock.cc:48
void getBgArea(int *x, int *y, int *width, int *height)
Return the area covered by the background image.
Definition textblock.cc:80
void getRefArea(int *xRef, int *yRef, int *widthRef, int *heightRef)
Return the "reference area".
Definition textblock.cc:91
core::style::Style * getStyle()
Return the style this background image is part of.
Definition textblock.cc:98
A Widget for rendering text blocks, i.e.
Definition textblock.hh:206
void drawLine(Line *line, core::View *view, core::Rectangle *area, core::DrawingContext *context)
int findParagraphOfWord(int wordIndex)
Find the paragraph of word wordIndex.
void drawWord0(int wordIndex1, int wordIndex2, const char *text, int totalWidth, bool drawHyphen, core::style::Style *style, core::View *view, core::Rectangle *area, int xWidget, int yWidgetBase)
TODO Comment.
void calcTextSizes(const char *text, size_t textLen, core::style::Style *style, int numBreaks, int *breakPos, core::Requisition *wordSize)
void breakAdded()
Called directly after a (line or paragraph) break has been added.
void getExtremesSimpl(core::Extremes *extremes)
Simple variant, to be implemented by widgets with extremes not depending on positions.
Definition textblock.cc:467
void changeWordStyle(int from, int to, core::style::Style *style, bool includeFirstSpace, bool includeLastSpace)
void accumulateWordData(int wordIndex)
void addWidget(core::Widget *widget, core::style::Style *style)
Add a widget (word type) to the page.
void getWordExtremes(Word *word, core::Extremes *extremes)
Get the extremes of a word within a textblock.
Definition textblock.cc:457
void addSpace(core::style::Style *style)
?
lout::misc::NotSoSimpleVector< Word > * words
Definition textblock.hh:611
core::SizeParams sizeRequestParams
Definition textblock.hh:578
int yOffsetOfLineCreated(Line *line)
Includes margin, border, and padding.
void correctLastWordExtremes()
Called when something changed for the last word (space, hyphens etc.).
void setWordImgRenderer(int wordNo)
void enterNotifyImpl(core::EventCrossing *event)
void changeLinkColor(int link, int newColor)
void widgetRefSizeChanged(int externalIndex)
Called by an implementation of dw::oof::OutOfFlowMgr (actually only OOFPosRelMgr) for the generator o...
int numSizeReferences
Definition textblock.hh:619
Widget * getExtremesReference(int index)
See Sizes of Dillo Widgets (or Size requisitions depending on positions).
Definition textblock.cc:533
struct dw::Textblock::@30 hlStart[core::HIGHLIGHT_NUM_LAYERS]
void handOverBreak(core::style::Style *style)
This function "hands" the last break of a page "over" to a parent page.
void processWord(int wordIndex)
void markSizeChange(int ref)
See Sizes of Dillo Widgets.
Definition textblock.cc:877
bool calcSizeOfWidgetInFlow(int wordIndex, Widget *widget, core::Requisition *size)
Calculate the size of a widget, and return whether it has to be positioned at the top of the line.
void oofSizeChanged(bool extremesChanged)
Called by an implementation of dw::oof::OutOfFlowMgr when the size of the container has changed,...
int numGetExtremesReferences()
See Sizes of Dillo Widgets (or Size requisitions depending on positions).
Definition textblock.cc:528
int getGeneratorX(int oofmIndex)
Return position relative to container, not regarding margin/border/padding, Called by OOFFloatsMgr to...
void fillParagraphs()
Counter part to rewrap(), but for extremes, not size calculation.
static void setStretchabilityFactor(int stretchabilityFactor)
Definition textblock.cc:201
void rewrap()
Rewrap the page from the line from which this is necessary.
void drawSpace(int wordIndex, core::View *view, core::Rectangle *area, int xWidget, int yWidgetBase)
void sizeAllocateImpl(core::Allocation *allocation)
See Sizes of Dillo Widgets.
Definition textblock.cc:569
static const char * hyphenDrawChar
The character which is used to draw a hyphen at the end of a line, either caused by automatic hyphena...
Definition textblock.hh:296
core::Iterator * iterator(core::Content::Type mask, bool atEnd)
Return an iterator for this widget.
void calcExtraSpaceImpl(int numPos, Widget **references, int *x, int *y)
Definition textblock.cc:734
int findLineIndexWhenNotAllocated(int y)
int lineYOffsetWidget(Line *line, core::Allocation *allocation)
Definition textblock.hh:712
void cleanupWord(int wordNo)
void calcTextOffset(int lineIndex, int totalWidth)
Word * findWord(int x, int y, bool *inSpace)
Find the index of the word, or -1.
static void setPenaltyHyphen(int penaltyHyphen)
Definition textblock.cc:175
void calcTextSize(const char *text, size_t len, core::style::Style *style, core::Requisition *size, bool isStart, bool isEnd)
Calculate the size of a text word.
void notifySetParent()
This method is called after a widget has been added to a parent.
Definition textblock.cc:546
RegardingBorder * getWidgetRegardingBorderForLine(Line *line)
void setBreakOption(Word *word, core::style::Style *style, int breakPenalty1, int breakPenalty2, bool forceBreak)
Set a break option, if allowed by the style.
void drawWord(Line *line, int wordIndex1, int wordIndex2, core::View *view, core::Rectangle *area, int xWidget, int yWidgetBase)
Draw a word of text.
int numSizeRequestReferences()
See Sizes of Dillo Widgets (or Size requisitions depending on positions).
Definition textblock.cc:422
static void setPenaltyEmDashLeft(int penaltyLeftEmDash)
Definition textblock.cc:185
int getAvailHeightOfChild(core::Widget *child, bool forceValue)
Definition textblock.cc:809
int nonTemporaryLines
Definition textblock.hh:610
bool limitTextWidth
Definition textblock.hh:572
lout::misc::SimpleVector< Anchor > * anchors
Definition textblock.hh:612
bool affectsSizeChangeContainerChild(Widget *child)
Definition textblock.cc:834
int yOffsetOfLineToBeCreated(int *lastMargin=NULL)
Includes margin, border, and padding.
void setSpaceImgRenderer(int wordNo)
static int stretchabilityFactor
...
Definition textblock.hh:570
static void setPenaltyHyphen2(int penaltyHyphen2)
Definition textblock.cc:180
bool addAnchor(const char *name, core::style::Style *style)
Add an anchor to the page.
static void setPenaltyEmDashRight2(int penaltyRightEmDash2)
Definition textblock.cc:196
void addText(const char *text, size_t len, core::style::Style *style)
Add a word to the page structure.
int getGeneratorY(int oofmIndex)
Return position relative to container, not regarding margin/border/padding, Called by OOFFloatsMgr to...
struct dw::Textblock::@30 hlEnd[core::HIGHLIGHT_NUM_LAYERS]
bool findSizeRequestReference(Widget *reference, int *xRef=NULL, int *yRef=NULL)
bool isBlockLevel()
Definition textblock.cc:938
void drawText(core::View *view, core::style::Style *style, core::style::Color::Shading shading, int x, int y, const char *text, int start, int len, bool isStart, bool isEnd)
void addBreakOption(core::style::Style *style, bool forceBreak)
Add a break option (see setBreakOption() for details).
int calcVerticalBorder(int widgetPadding, int widgetBorder, int widgetMargin, int lineBorderTotal, int lineMarginTotal)
Definition textblock.cc:432
int getMaxGeneratorWidth()
int getGeneratorRest(int oofmIndex)
static int penalties[PENALTY_NUM][2]
The penalties for hyphens and other, multiplied by 100.
Definition textblock.hh:565
void leaveNotifyImpl(core::EventCrossing *event)
void resizeDrawImpl()
Called after sizeAllocateImpl() to redraw necessary areas.
Definition textblock.cc:857
bool isBreakAllowed(core::style::Style *style)
static void setPenaltyEmDashRight(int penaltyRightEmDash)
Definition textblock.cc:191
bool usesAvailWidth()
Must be implemengted by a method returning true, when getAvailWidth() is called.
Definition textblock.cc:852
void addText0(const char *text, size_t len, short flags, core::style::Style *style, core::Requisition *size)
Add a word (without hyphens) to the page structure.
Widget * getWidgetAtPointLevel(int x, int y, int level, core::GettingWidgetAtPointContext *context)
int getGeneratorWidth()
Return width including margin/border/padding Called by OOFFloatsMgr to position floats.
void decorateText(core::View *view, core::style::Style *style, core::style::Color::Shading shading, int x, int yBase, int width)
int findLineOfWord(int wordIndex)
Find the line of word wordIndex.
void removeChild(Widget *child)
bool mustQueueResize
Definition textblock.hh:557
int textWidth(const char *text, int start, int len, core::style::Style *style, bool isStart, bool isEnd)
void notifySetAsTopLevel()
This method is called after a widget has been set as the top of a widget tree.
Definition textblock.cc:538
void addParbreak(int space, core::style::Style *style)
Cause a paragraph break.
void fillSpace(int wordNo, core::style::Style *style)
Widget * sizeReferences[NUM_OOFM]
Definition textblock.hh:620
bool buttonPressImpl(core::EventButton *event)
Definition textblock.cc:943
static int CLASS_ID
Definition textblock.hh:867
void queueDrawRange(int index1, int index2)
Widget * sizeRequestReference(int index)
See Sizes of Dillo Widgets (or Size requisitions depending on positions).
Definition textblock.cc:427
bool isPossibleOOFContainer(int oofmIndex)
void containerSizeChangedForChildren()
Definition textblock.cc:819
void updateReference(int ref)
Update content in flow, down from ref.
bool usesMaxGeneratorWidth()
void fillWord(int wordNo, int width, int ascent, int descent, short flags, core::style::Style *style)
bool motionNotifyImpl(core::EventMotion *event)
Definition textblock.cc:958
bool sendSelectionEvent(core::SelectionState::EventType eventType, core::MousePositionEvent *event)
Send event to selection.
void addLinebreak(core::style::Style *style)
int findLineIndexWhenAllocated(int y)
void removeSpaceImgRenderer(int wordNo)
void initWord(int wordNo)
Basic initialization, which is neccessary before fillWord.
bool hasListitemValue
Definition textblock.hh:531
void sizeRequestImpl(core::Requisition *requisition, int numPos, Widget **references, int *x, int *y)
The ascent of a textblock is the ascent of the first line, plus padding/border/margin.
Definition textblock.cc:308
int wrapRefParagraphs
Definition textblock.hh:583
bool buttonReleaseImpl(core::EventButton *event)
Definition textblock.cc:948
Textblock(bool limitTextWidth, bool treatAsInline=false)
Definition textblock.cc:206
Word * addWord(int width, int ascent, int descent, short flags, core::style::Style *style)
Add a new word (text, widget etc.) to a page.
int getAvailWidthOfChild(core::Widget *child, bool forceValue)
Computes the content width available of a child widget.
Definition textblock.cc:755
void removeWordImgRenderer(int wordNo)
static DivChar divChars[NUM_DIV_CHARS]
Definition textblock.hh:294
void markExtremesChange(int ref)
See Sizes of Dillo Widgets.
Definition textblock.cc:911
lout::misc::SimpleVector< Paragraph > * paragraphs
Definition textblock.hh:609
void drawLevel(core::View *view, core::Rectangle *area, int level, core::DrawingContext *context)
bool ignoreLine1OffsetSometimes
Definition textblock.hh:555
int lineYOffsetCanvas(Line *line, core::Allocation *allocation)
Definition textblock.hh:722
lout::misc::SimpleVector< Line > * lines
Definition textblock.hh:608
bool isPossibleOOFContainerParent(int oofmIndex)
int findLineIndex(int y)
Find the first line index that includes y, which is given in widget coordinates.
Set at the top when drawing.
Definition types.hh:295
Represents a button press or release event.
Definition events.hh:58
Represents a enter or leave notify event.
Definition events.hh:75
Represents a mouse motion event.
Definition events.hh:68
Set at the top when getting the widget at the point.
Definition types.hh:313
Iterators are used to iterate through the contents of a widget.
Definition iterator.hh:20
virtual void unref()
Delete the iterator.
Definition iterator.cc:82
lout::misc::ZoneAllocator * textZone
Definition layout.hh:276
int textWidth(style::Font *font, const char *text, int len)
Definition layout.hh:349
int nextGlyph(const char *text, int idx)
Definition layout.hh:364
bool emitLinkEnter(Widget *w, int link, int img, int x, int y)
Definition layout.hh:261
char * textToUpper(const char *text, int len)
Definition layout.hh:354
char * textToLower(const char *text, int len)
Definition layout.hh:359
ButtonState state
Definition events.hh:42
Base class for all mouse events related to a specific position.
Definition events.hh:49
dw::core::Shape implemtation for simple rectangles.
Definition types.hh:70
Hold arguments passed to dw::core::Widget::sizeRequest and dw::core::Widget::getExtremes,...
Definition tools.hh:19
void fill(int numPos, Widget **references, int *x, int *y)
Definition tools.cc:65
void forChild(Widget *parent, Widget *child, int xRel, int yRel, SizeParams *childParams)
Definition tools.cc:88
Widget ** getReferences()
Definition tools.hh:55
bool findReference(Widget *reference, int *x, int *y)
Definition tools.cc:130
static bool handledByStackingContextMgr(Widget *widget)
An interface to encapsulate platform dependent drawing.
Definition view.hh:17
virtual void drawText(style::Font *font, style::Color *color, style::Color::Shading shading, int x, int y, const char *text, int len)=0
virtual void drawRectangle(style::Color *color, style::Color::Shading shading, bool filled, int x, int y, int width, int height)=0
The base class of all dillo widgets.
Definition widget.hh:24
virtual void setStyle(style::Style *style)
Change the style of a widget.
Definition widget.cc:1233
void setGenerator(Widget *generator)
Definition widget.hh:446
Allocation * getAllocation()
Definition widget.hh:450
void sizeAllocate(Allocation *allocation)
Wrapper for Widget::sizeAllocateImpl, calls the latter only when needed.
Definition widget.cc:1126
void setWidgetReference(WidgetReference *widgetReference)
Definition widget.hh:560
Extremes extremes
Analogue to dw::core::Widget::requisition.
Definition widget.hh:146
Layout * layout
Definition widget.hh:189
Widget * container
The containing widget, equivalent to the "containing block" defined by CSS.
Definition widget.hh:126
bool intersects(Widget *refWidget, Rectangle *area, Rectangle *intersection)
Calculates the intersection of the visible allocation (i.
Definition widget.cc:139
Allocation allocation
The current allocation: size and position, always relative to the canvas.
Definition widget.hh:183
virtual void draw(View *view, Rectangle *area, DrawingContext *context)=0
Area is given in widget coordinates.
void setButtonSensitive(bool buttonSensitive)
Definition widget.cc:1468
Widget * getParent()
Definition widget.hh:552
int boxDiffWidth()
Definition widget.hh:461
int parentRef
This value is defined by the parent widget, and used for incremential resizing.
Definition widget.hh:175
int getAvailWidth(bool forceValue)
Return available width including margin/border/padding (extraSpace?), not only the content width.
Definition widget.cc:649
void correctRequisition(Requisition *requisition, void(*splitHeightFun)(int, int *, int *), bool allowDecreaseWidth, bool allowDecreaseHeight)
Definition widget.cc:744
style::Style * getStyle()
Definition widget.hh:448
Requisition requisition
Size_request() stores the result of the last call of size_request_impl().
Definition widget.hh:140
Widget * getWidgetAtPointInterrupted(int x, int y, GettingWidgetAtPointContext *context)
Definition widget.cc:222
style::Box extraSpace
Space around the margin box.
Definition widget.hh:199
void queueDrawArea(int x, int y, int width, int height)
Definition widget.cc:285
bool selectionHandleEvent(SelectionState::EventType eventType, Iterator *it, int charPos, int linkNo, MousePositionEvent *event)
Definition widget.hh:392
void setCursor(style::Cursor cursor)
Definition widget.hh:377
bool extremesQueued()
Definition widget.hh:436
bool extremesChanged()
Definition widget.hh:440
void changeAnchor(char *name, int y)
Definition widget.hh:369
void setParent(Widget *parent)
Definition widget.cc:231
int boxRestWidth()
Definition widget.hh:459
int boxRestHeight()
Definition widget.hh:464
virtual Widget * getWidgetAtPoint(int x, int y, GettingWidgetAtPointContext *context)
Definition widget.cc:211
void drawInterruption(View *view, Rectangle *area, DrawingContext *context)
See Interrupted drawing for details.
Definition widget.cc:201
Widget * parent
The parent widget, NULL for top-level widgets.
Definition widget.hh:107
style::Style * style
Definition widget.hh:130
void containerSizeChanged()
Definition widget.cc:408
void queueResize(int ref, bool extremesChanged, bool fast)
This method should be called, when a widget changes its size.
Definition widget.cc:309
style::Color * getBgColor()
Get the actual background of a widget.
Definition widget.cc:1348
bool wasAllocated()
Definition widget.hh:441
void removeAnchor(char *name)
Definition widget.hh:372
void correctExtremes(Extremes *extremes, bool useAdjustmentWidth)
Definition widget.cc:821
void getExtremes(Extremes *extremes, int numPos=0, Widget **references=NULL, int *x=NULL, int *y=NULL)
Wrapper for Widget::getExtremesImpl().
Definition widget.cc:1014
void drawBox(View *view, style::Style *style, Rectangle *area, int x, int y, int width, int height, bool inverse)
Draw borders and background of a widget part, which allocation is given by (x, y, width,...
Definition widget.cc:1371
static Color * create(Layout *layout, int color)
Definition style.cc:528
TextTransform textTransform
Definition style.hh:545
StyleImage * backgroundImage
Definition style.hh:536
void setBorderColor(Color *val)
Definition style.hh:584
void putExternalImgRenderer(ImgRenderer *ir)
Add an additional ImgRenderer, especially used for drawing.
Definition style.hh:890
void removeExternalImgRenderer(ImgRenderer *ir)
Remove a previously added additional ImgRenderer.
Definition style.hh:896
static Style * create(StyleAttrs *attrs)
Definition style.hh:628
virtual void onMotion()
Definition style.hh:673
virtual void onLeave()
Definition style.hh:672
virtual void onEnter()
Definition style.hh:671
static bool testWidgetFixedlyPositioned(Widget *widget)
int getParentRefInFlowSubRef(int parentRef)
void sizeAllocateStart(core::Allocation *allocation)
OutOfFlowMgr * searchOutOfFlowMgr(int oofmIndex)
virtual int getGeneratorWidth()
Return width including margin/border/padding Called by OOFFloatsMgr to position floats.
bool isWidgetOOF(Widget *widget)
bool doesWidgetOOFInterruptDrawing(Widget *widget)
static bool testWidgetAbsolutelyPositioned(Widget *widget)
bool isParentRefOOF(int parentRef)
static const char * stackingLevelText(int level)
oof::OutOfFlowMgr * getWidgetOutOfFlowMgr(Widget *widget)
OOFAwareWidget * oofContainer[NUM_OOFM]
static bool isOOFContainer(Widget *widget, int oofmIndex)
void correctRequisitionByOOF(core::Requisition *requisition, void(*splitHeightFun)(int, int *, int *))
int getParentRefOOFSubRef(int parentRef)
int makeParentRefOOF(int oofmIndex, int oofmSubRef)
void correctExtremesByOOF(core::Extremes *extremes)
static const char * OOFM_NAME[NUM_OOFM]
static int getOOFMIndex(Widget *widget)
oof::OutOfFlowMgr * getParentRefOutOfFlowMgr(int parentRef)
static bool testWidgetFloat(Widget *widget)
static bool testWidgetOutOfFlow(Widget *widget)
int makeParentRefInFlow(int inFlowSubRef)
int getWidgetInFlowSubRef(Widget *widget)
Represents additional data for OOF containers.
virtual void addWidgetInFlow(OOFAwareWidget *widget, OOFAwareWidget *parent, int externalIndex)=0
virtual int addWidgetOOF(core::Widget *widget, OOFAwareWidget *generator, int externalIndex)=0
virtual void calcWidgetRefSize(core::Widget *widget, core::Requisition *size)=0
virtual void markSizeChange(int ref)=0
virtual int getAvailHeightOfChild(core::Widget *child, bool forceValue)=0
virtual int getAvailWidthOfChild(core::Widget *child, bool forceValue)=0
virtual bool dealingWithSizeOfChild(core::Widget *child)=0
virtual void markExtremesChange(int ref)=0
bool instanceOf(int otherClassId)
Returns, whether this class is an instance of the class, given by otherClassId, or of a sub class of ...
Definition identity.cc:105
void registerName(const char *className, int *classId)
This method must be called in the constructor for the sub class.
Definition identity.cc:83
const char * strndup(const char *str, size_t t)
Definition misc.hh:678
#define DBG_OBJ_ENTER0(aspect, prio, funname)
#define DBG_OBJ_SET_BOOL_O(obj, var, val)
#define DBG_OBJ_DELETE()
#define DBG_OBJ_CREATE(klass)
#define DBG_OBJ_SET_BOOL(var, val)
#define DBG_OBJ_MSG_END()
#define DBG_OBJ_MSGF(aspect, prio, fmt,...)
#define DBG_OBJ_SET_NUM(var, val)
#define DBG_OBJ_MSG(aspect, prio, msg)
#define DBG_OBJ_ENTER(aspect, prio, funname, fmt,...)
#define DBG_OBJ_LEAVE()
#define DBG_OBJ_MSG_START()
#define DBG_OBJ_ASSOC_CHILD(child)
#define DBG_OBJ_ARRSET_PTR(var, ind, val)
#define DBG_OBJ_ARRATTRSET_NUM(var, ind, attr, val)
#define DBG_OBJ_SET_NUM_O(obj, var, val)
#define DBG_OBJ_LEAVE_VAL(fmt,...)
int multiplyWithPerLengthRounded(int x, Length l)
Like multiplyWithPerLength, but rounds to nearest integer instead of down.
Definition style.hh:483
@ TEXT_TRANSFORM_LOWERCASE
Definition style.hh:271
@ TEXT_TRANSFORM_UPPERCASE
Definition style.hh:270
@ TEXT_TRANSFORM_CAPITALIZE
Definition style.hh:269
@ TEXT_TRANSFORM_NONE
Definition style.hh:268
@ TEXT_DECORATION_OVERLINE
Definition style.hh:353
@ TEXT_DECORATION_LINE_THROUGH
Definition style.hh:354
@ TEXT_DECORATION_UNDERLINE
Definition style.hh:352
bool isAbsLength(Length l)
Returns true if l is an absolute length.
Definition style.hh:442
int absLengthVal(Length l)
Returns the value of a length in pixels, as an integer.
Definition style.hh:451
@ LENGTH_AUTO
Represents "auto" lengths.
Definition style.hh:494
@ WHITE_SPACE_PRE_LINE
Definition style.hh:363
@ WHITE_SPACE_PRE_WRAP
Definition style.hh:362
@ BUTTON1_MASK
Definition events.hh:20
@ HIGHLIGHT_NUM_LAYERS
Definition types.hh:46
void splitHeightPreserveAscent(int height, int *ascent, int *descent)
Definition widget.cc:2010
Dw is in this namespace, or sub namespaces of this one.
Miscellaneous stuff, which does not fit anywhere else.
Definition misc.cc:31
T min(T a, T b)
Definition misc.hh:19
T max(T a, T b)
Definition misc.hh:20
int roundInt(double d)
Definition misc.hh:61
void assertNotReached()
Definition misc.hh:35
const char * boolToStr(bool b)
Definition misc.hh:87
Stuff dealing with Unicode characters: UTF-8, character classes etc.
Definition unicode.cc:28
const char * nextUtf8Char(const char *s)
Definition unicode.cc:110
SpaceImgRenderer * spaceImgRenderer
Definition textblock.hh:499
core::style::Style * style
Definition textblock.hh:492
WordImgRenderer * wordImgRenderer
Definition textblock.hh:498
core::Requisition size
Definition textblock.hh:463
BadnessAndPenalty badnessAndPenalty
Definition textblock.hh:489
core::style::Style * spaceStyle
Definition textblock.hh:493
core::Content content
Definition textblock.hh:475
@ DIV_CHAR_AT_EOL
Must be drawn with a hyphen, when at the end of the line.
Definition textblock.hh:434
@ CAN_BE_HYPHENATED
Can be hyphenated automatically.
Definition textblock.hh:432
@ PERM_DIV_CHAR
Is or ends with a "division character", which is part of the word.
Definition textblock.hh:437
@ DRAW_AS_ONE_TEXT
This word must be drawn, together with the following word(s), by only one call of View::drawText(),...
Definition textblock.hh:442
Represents the allocation, i.e.
Definition types.hh:164
@ WIDGET_OOF_REF
reference to a widget out of flow (OOF); this widget (containing this content) is only the generator ...
Definition types.hh:217
@ WIDGET_IN_FLOW
widget in normal flow, so that this widget (containing this content) is both container (parent) and g...
Definition types.hh:207
const char * text
Definition types.hh:236
Widget * widget
Definition types.hh:237
static Content::Type maskForSelection(bool followReferences)
Definition types.cc:271
WidgetReference * widgetReference
Definition types.hh:238
static dw::core::style::Tooltip * hoverTooltip
Definition textblock.cc:37
#define PRINTF(fmt,...)
Definition textblock.hh:11
#define DBG_MSG_WORD(aspect, prio, prefix, n, suffix)
Definition textblock.hh:981
#define PUTCHAR(ch)
Definition textblock.hh:12
#define DBG_SET_WORD_SIZE(n)
Definition textblock.hh:971
#define DBG_SET_WORD(n)
Definition textblock.hh:934