Dillo v3.1.1-46-g8a360e32
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 = new char[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 delete[] text;
1330 }
1331}
1332
1336void Textblock::drawWord0 (int wordIndex1, int wordIndex2,
1337 const char *text, int totalWidth, bool drawHyphen,
1339 core::Rectangle *area, int xWidget, int yWidgetBase)
1340{
1341 int xWorld = allocation.x + xWidget;
1342 int yWorldBase;
1343
1344 /* Adjust the text baseline if the word is <SUP>-ed or <SUB>-ed. */
1346 yWidgetBase += style->font->ascent / 3;
1347 else if (style->valign == core::style::VALIGN_SUPER) {
1348 yWidgetBase -= style->font->ascent / 2;
1349 }
1350 yWorldBase = yWidgetBase + allocation.y;
1351
1352 bool isStartTotal = words->getRef(wordIndex1)->flags & Word::WORD_START;
1353 bool isEndTotal = words->getRef(wordIndex2)->flags & Word::WORD_START;
1355 yWorldBase, text, 0, strlen (text), isStartTotal, isEndTotal);
1356
1357 if (style->textDecoration)
1359 yWorldBase, totalWidth);
1360
1361 for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
1362 if (wordIndex1 <= hlEnd[layer].index &&
1363 wordIndex2 >= hlStart[layer].index) {
1364 const int wordLen = strlen (text);
1365 int xStart, width;
1366 int firstCharIdx;
1367 int lastCharIdx;
1368
1369 if (hlStart[layer].index < wordIndex1)
1370 firstCharIdx = 0;
1371 else {
1372 firstCharIdx =
1373 misc::min (hlStart[layer].nChar,
1374 (int)strlen (words->getRef(hlStart[layer].index)
1375 ->content.text));
1376 for (int i = wordIndex1; i < hlStart[layer].index; i++)
1377 // It can be assumed that all words from wordIndex1 to
1378 // wordIndex2 have content type TEXT.
1379 firstCharIdx += strlen (words->getRef(i)->content.text);
1380 }
1381
1382 if (hlEnd[layer].index > wordIndex2)
1383 lastCharIdx = wordLen;
1384 else {
1385 lastCharIdx =
1386 misc::min (hlEnd[layer].nChar,
1387 (int)strlen (words->getRef(hlEnd[layer].index)
1388 ->content.text));
1389 for (int i = wordIndex1; i < hlEnd[layer].index; i++)
1390 // It can be assumed that all words from wordIndex1 to
1391 // wordIndex2 have content type TEXT.
1392 lastCharIdx += strlen (words->getRef(i)->content.text);
1393 }
1394
1395 xStart = xWorld;
1396 if (firstCharIdx)
1397 xStart += textWidth (text, 0, firstCharIdx, style,
1398 isStartTotal,
1399 isEndTotal && text[firstCharIdx] == 0);
1400 // With a hyphen, the width is a bit longer than totalWidth,
1401 // and so, the optimization to use totalWidth is not correct.
1402 if (!drawHyphen && firstCharIdx == 0 && lastCharIdx == wordLen)
1403 width = totalWidth;
1404 else
1405 width = textWidth (text, firstCharIdx,
1406 lastCharIdx - firstCharIdx, style,
1407 isStartTotal && firstCharIdx == 0,
1408 isEndTotal && text[lastCharIdx] == 0);
1409 if (width > 0) {
1410 /* Highlight text */
1411 core::style::Color *wordBgColor;
1412
1413 if (!(wordBgColor = style->backgroundColor))
1414 wordBgColor = getBgColor();
1415
1416 /* Draw background for highlighted text. */
1417 view->drawRectangle (
1418 wordBgColor, core::style::Color::SHADING_INVERSE, true, xStart,
1419 yWorldBase - style->font->ascent, width,
1421
1422 /* Highlight the text. */
1424 yWorldBase, text, firstCharIdx,
1425 lastCharIdx - firstCharIdx,
1426 isStartTotal && firstCharIdx == 0,
1427 isEndTotal && lastCharIdx == wordLen);
1428
1429 if (style->textDecoration)
1431 xStart, yWorldBase, width);
1432 }
1433 }
1434 }
1435}
1436
1437/*
1438 * Draw a space.
1439 */
1440void Textblock::drawSpace(int wordIndex, core::View *view,
1441 core::Rectangle *area, int xWidget, int yWidgetBase)
1442{
1443 Word *word = words->getRef(wordIndex);
1444 int xWorld = allocation.x + xWidget;
1445 int yWorldBase;
1447 bool highlight = false;
1448
1449 /* Adjust the space baseline if it is <SUP>-ed or <SUB>-ed */
1451 yWidgetBase += style->font->ascent / 3;
1452 else if (style->valign == core::style::VALIGN_SUPER) {
1453 yWidgetBase -= style->font->ascent / 2;
1454 }
1455 yWorldBase = allocation.y + yWidgetBase;
1456
1457 for (int layer = 0; layer < core::HIGHLIGHT_NUM_LAYERS; layer++) {
1458 if (hlStart[layer].index <= wordIndex &&
1459 hlEnd[layer].index > wordIndex) {
1460 highlight = true;
1461 break;
1462 }
1463 }
1464 if (highlight) {
1465 core::style::Color *spaceBgColor;
1466
1467 if (!(spaceBgColor = style->backgroundColor))
1468 spaceBgColor = getBgColor();
1469
1470 view->drawRectangle (
1471 spaceBgColor, core::style::Color::SHADING_INVERSE, true, xWorld,
1472 yWorldBase - style->font->ascent, word->effSpace,
1474 }
1475 if (style->textDecoration) {
1476 core::style::Color::Shading shading = highlight ?
1479
1480 decorateText(view, style, shading, xWorld, yWorldBase, word->effSpace);
1481 }
1482}
1483
1484/*
1485 * Paint a line
1486 * - x and y are toplevel dw coordinates (Question: what Dw? Changed. Test!)
1487 * - area is used always (ev. set it to event->area)
1488 * - event is only used when is_expose
1489 */
1491 core::DrawingContext *context)
1492{
1493 DBG_OBJ_ENTER ("draw", 0, "drawLine", "..., [%d, %d, %d * %d]",
1494 area->x, area->y, area->width, area->height);
1495
1496 int xWidget = line->textOffset;
1497 int yWidgetBase = lineYOffsetWidget (line) + line->borderAscent;
1498
1499 DBG_OBJ_MSGF ("draw", 1, "line from %d to %d (%d words), at (%d, %d)",
1500 line->firstWord, line->lastWord, words->size (),
1501 xWidget, yWidgetBase);
1502 DBG_MSG_WORD ("draw", 1, "<i>line starts with: </i>", line->firstWord, "");
1503 DBG_MSG_WORD ("draw", 1, "<i>line ends with: </i>", line->lastWord, "");
1504
1506
1507 for (int wordIndex = line->firstWord;
1508 wordIndex <= line->lastWord && xWidget < area->x + area->width;
1509 wordIndex++) {
1510 DBG_MSG_WORD ("draw", 2, "<i>drawing: </i>", wordIndex, "");
1511
1512 Word *word = words->getRef (wordIndex);
1513 int wordSize = word->size.width;
1514
1515 if (xWidget + wordSize + word->hyphenWidth + word->effSpace >= area->x) {
1516 if (word->content.type == core::Content::TEXT ||
1518
1519 if (word->size.width > 0) {
1521 core::Widget *child = word->content.widget;
1522 core::Rectangle childArea;
1524 (child) &&
1525 child->intersects (this, area, &childArea))
1526 child->draw (view, &childArea, context);
1527 } else {
1528 int wordIndex2 = wordIndex;
1529 while (wordIndex2 < line->lastWord &&
1530 (words->getRef(wordIndex2)->flags
1532 word->style == words->getRef(wordIndex2 + 1)->style)
1533 wordIndex2++;
1534
1535 drawWord(line, wordIndex, wordIndex2, view, area,
1536 xWidget, yWidgetBase);
1537 wordSize = 0;
1538 for (int i = wordIndex; i <= wordIndex2; i++)
1539 wordSize += words->getRef(i)->size.width;
1540
1541 wordIndex = wordIndex2;
1542 word = words->getRef(wordIndex);
1543 }
1544 }
1545
1546 if (word->effSpace > 0 && wordIndex < line->lastWord &&
1547 words->getRef(wordIndex + 1)->content.type !=
1549 if (word->spaceStyle->hasBackground ())
1550 drawBox (view, word->spaceStyle, area,
1551 xWidget + wordSize,
1552 yWidgetBase - line->borderAscent, word->effSpace,
1553 line->borderAscent + line->borderDescent, false);
1554 drawSpace (wordIndex, view, area, xWidget + wordSize,
1555 yWidgetBase);
1556 }
1557
1558 }
1559 }
1560 xWidget += wordSize + word->effSpace;
1561 }
1562
1563 DBG_OBJ_MSG_END ();
1564
1565 DBG_OBJ_LEAVE ();
1566}
1567
1577
1579{
1580 if (lines->size() == 0)
1581 return -1;
1582 else
1583 return
1585 getStyle()->borderWidth.top,
1586 getStyle()->margin.top
1587 + extraSpace.top,
1588 lines->getRef(0)->borderAscent,
1589 lines->getRef(0)->marginAscent));
1590}
1591
1593{
1594 assert (wasAllocated ());
1595 return findLineIndex (y, allocation.ascent);
1596}
1597
1598int Textblock::findLineIndex (int y, int ascent)
1599{
1600 DBG_OBJ_ENTER ("events", 0, "findLineIndex", "%d, %d", y, ascent);
1601
1602 core::Allocation alloc;
1603 alloc.ascent = ascent; // More is not needed.
1604
1605 int maxIndex = lines->size () - 1;
1606 int step, index, low = 0;
1607
1608 step = (lines->size() + 1) >> 1;
1609 while ( step > 1 ) {
1610 index = low + step;
1611 if (index <= maxIndex && lineYOffsetWidget (index, &alloc) <= y)
1612 low = index;
1613 step = (step + 1) >> 1;
1614 }
1615
1616 if (low < maxIndex && lineYOffsetWidget (low + 1, &alloc) <= y)
1617 low++;
1618
1619 /*
1620 * This new routine returns the line number between (top) and
1621 * (top + size.ascent + size.descent + breakSpace): the space
1622 * _below_ the line is considered part of the line. Old routine
1623 * returned line number between (top - previous_line->breakSpace)
1624 * and (top + size.ascent + size.descent): the space _above_ the
1625 * line was considered part of the line. This is important for
1626 * Dw_page_find_link() --EG
1627 * That function has now been inlined into Dw_page_motion_notify() --JV
1628 */
1629
1630 DBG_OBJ_LEAVE_VAL ("%d", low);
1631 return low;
1632}
1633
1637int Textblock::findLineOfWord (int wordIndex)
1638{
1639 if (wordIndex < 0 || wordIndex >= words->size () ||
1640 // Also regard not-yet-existing lines.
1641 lines->size () <= 0 || wordIndex > lines->getLastRef()->lastWord)
1642 return -1;
1643
1644 int high = lines->size () - 1, index, low = 0;
1645
1646 while (true) {
1647 index = (low + high) / 2;
1648 if (wordIndex >= lines->getRef(index)->firstWord) {
1649 if (wordIndex <= lines->getRef(index)->lastWord)
1650 return index;
1651 else
1652 low = index + 1;
1653 } else
1654 high = index - 1;
1655 }
1656}
1657
1662{
1663 int high = paragraphs->size () - 1, index, low = 0;
1664
1665 if (wordIndex < 0 || wordIndex >= words->size () ||
1666 // It may be that the paragraphs list is incomplete. But look
1667 // also at fillParagraphs, where this method is called.
1668 (paragraphs->size () == 0 ||
1669 wordIndex > paragraphs->getLastRef()->lastWord))
1670 return -1;
1671
1672 while (true) {
1673 index = (low + high) / 2;
1674 if (wordIndex >= paragraphs->getRef(index)->firstWord) {
1675 if (wordIndex <= paragraphs->getRef(index)->lastWord)
1676 return index;
1677 else
1678 low = index + 1;
1679 } else
1680 high = index - 1;
1681 }
1682}
1683
1687Textblock::Word *Textblock::findWord (int x, int y, bool *inSpace)
1688{
1689 int lineIndex, wordIndex;
1690 int xCursor, lastXCursor, yWidgetBase;
1691 Line *line;
1692 Word *word;
1693
1694 *inSpace = false;
1695
1696 if ((lineIndex = findLineIndexWhenAllocated (y)) >= lines->size ())
1697 return NULL;
1698 line = lines->getRef (lineIndex);
1699 yWidgetBase = lineYOffsetWidget (line) + line->borderAscent;
1700 if (yWidgetBase + line->borderDescent <= y)
1701 return NULL;
1702
1703 xCursor = line->textOffset;
1704 for (wordIndex = line->firstWord; wordIndex <= line->lastWord;wordIndex++) {
1705 word = words->getRef (wordIndex);
1706 lastXCursor = xCursor;
1707 xCursor += word->size.width + word->effSpace;
1708 if (lastXCursor <= x && xCursor > x) {
1709 if (x >= xCursor - word->effSpace) {
1710 if (wordIndex < line->lastWord &&
1711 (words->getRef(wordIndex + 1)->content.type !=
1713 y > yWidgetBase - word->spaceStyle->font->ascent &&
1714 y <= yWidgetBase + word->spaceStyle->font->descent) {
1715 *inSpace = true;
1716 return word;
1717 }
1718 } else {
1719 if (y > yWidgetBase - word->size.ascent &&
1720 y <= yWidgetBase + word->size.descent)
1721 return word;
1722 }
1723 break;
1724 }
1725 }
1726
1727 return NULL;
1728}
1729
1731 int level, core::DrawingContext *context)
1732{
1733 DBG_OBJ_ENTER ("draw", 0, "Textblock::drawLevel", "(%d, %d, %d * %d), %s",
1734 area->x, area->y, area->width, area->height,
1735 stackingLevelText (level));
1736
1737 switch (level) {
1738 case SL_IN_FLOW:
1739 for (int lineIndex = findLineIndexWhenAllocated (area->y);
1740 lineIndex < lines->size (); lineIndex++) {
1741 Line *line = lines->getRef (lineIndex);
1742 if (lineYOffsetWidget (line) >= area->y + area->height)
1743 break;
1744
1745 DBG_OBJ_MSGF ("draw", 0, "line %d (of %d)", lineIndex, lines->size ());
1746 drawLine (line, view, area, context);
1747 }
1748 break;
1749
1750 case SL_OOF_REF:
1751 // TODO Inefficient. Perhaps store OOF references in seperate
1752 // (much smaller!) list.
1753 for (int oofmIndex = 0; oofmIndex < NUM_OOFM; oofmIndex++) {
1754 for (int wordIndex = 0; wordIndex < words->size (); wordIndex++) {
1755 Word *word = words->getRef (wordIndex);
1758 == oofmIndex &&
1760 word->content.widget->drawInterruption (view, area, context);
1761 }
1762 }
1763 break;
1764
1765 default:
1766 OOFAwareWidget::drawLevel (view, area, level, context);
1767 break;
1768 }
1769
1770 DBG_OBJ_LEAVE ();
1771}
1772
1776Textblock::Word *Textblock::addWord (int width, int ascent, int descent,
1778{
1779 DBG_OBJ_ENTER ("construct.word", 0, "addWord", "%d * (%d + %d), %d, %p",
1780 width, ascent, descent, flags, style);
1781
1782 if (lineBreakWidth == -1) {
1784 DBG_OBJ_SET_NUM ("lineBreakWidth", lineBreakWidth);
1785 }
1786
1787 words->increase ();
1788 DBG_OBJ_SET_NUM ("words.size", words->size ());
1789 int wordNo = words->size () - 1;
1790 initWord (wordNo);
1791 fillWord (wordNo, width, ascent, descent, flags, style);
1792
1793 DBG_OBJ_LEAVE ();
1794 return words->getRef (wordNo);
1795}
1796
1800void Textblock::initWord (int wordNo)
1801{
1802 Word *word = words->getRef (wordNo);
1803
1804 word->style = word->spaceStyle = NULL;
1805 word->wordImgRenderer = NULL;
1806 word->spaceImgRenderer = NULL;
1807}
1808
1809void Textblock::cleanupWord (int wordNo)
1810{
1811 Word *word = words->getRef (wordNo);
1812
1814 delete word->content.widget;
1816 delete word->content.widgetReference;
1819 removeWordImgRenderer (wordNo);
1820 removeSpaceImgRenderer (wordNo);
1821
1822 word->style->unref ();
1823 word->spaceStyle->unref ();
1824}
1825
1827{
1828 Word *word = words->getRef (wordNo);
1829
1830 if (word->style && word->wordImgRenderer) {
1832 (word->wordImgRenderer);
1833 delete word->wordImgRenderer;
1834 word->wordImgRenderer = NULL;
1835 }
1836}
1837
1839{
1840 Word *word = words->getRef (wordNo);
1841
1842 if (word->style->backgroundImage) {
1843 word->wordImgRenderer = new WordImgRenderer (this, wordNo);
1845 (word->wordImgRenderer);
1846 } else
1847 word->wordImgRenderer = NULL;
1848}
1849
1851{
1852 Word *word = words->getRef (wordNo);
1853
1854 if (word->spaceStyle && word->spaceImgRenderer) {
1856 (word->spaceImgRenderer);
1857 delete word->spaceImgRenderer;
1858 word->spaceImgRenderer = NULL;
1859 }
1860}
1861
1863{
1864 Word *word = words->getRef (wordNo);
1865
1866 if (word->spaceStyle->backgroundImage) {
1867 word->spaceImgRenderer = new SpaceImgRenderer (this, wordNo);
1869 (word->spaceImgRenderer);
1870 } else
1871 word->spaceImgRenderer = NULL;
1872}
1873
1874void Textblock::fillWord (int wordNo, int width, int ascent, int descent,
1876{
1877 Word *word = words->getRef (wordNo);
1878
1879 word->size.width = width;
1880 word->size.ascent = ascent;
1881 word->size.descent = descent;
1882 DBG_SET_WORD_SIZE (wordNo);
1883 word->origSpace = word->effSpace = 0;
1884 word->hyphenWidth = 0;
1886 word->content.space = false;
1887 word->flags = flags;
1888
1889 removeWordImgRenderer (wordNo);
1890 removeSpaceImgRenderer (wordNo);
1891
1892 word->style = style;
1893 word->spaceStyle = style;
1894
1895 setWordImgRenderer (wordNo);
1896 setSpaceImgRenderer (wordNo);
1897
1898 style->ref ();
1899 style->ref ();
1900}
1901
1902/*
1903 * Get the width of a string of text.
1904 *
1905 * For "isStart" and "isEnd" see drawText.
1906 */
1907int Textblock::textWidth(const char *text, int start, int len,
1908 core::style::Style *style, bool isStart, bool isEnd)
1909{
1910 int ret = 0;
1911
1912 if (len > 0) {
1913 char *str = NULL;
1914
1915 switch (style->textTransform) {
1917 default:
1918 ret = layout->textWidth(style->font, text+start, len);
1919 break;
1921 str = layout->textToUpper(text+start, len);
1922 ret = layout->textWidth(style->font, str, strlen(str));
1923 break;
1925 str = layout->textToLower(text+start, len);
1926 ret = layout->textWidth(style->font, str, strlen(str));
1927 break;
1929 if (isStart) {
1930 /* \bug No way to know about non-ASCII punctuation. */
1931 bool initial_seen = false;
1932
1933 for (int i = 0; i < start; i++)
1934 if (!ispunct(text[i]))
1935 initial_seen = true;
1936 if (initial_seen) {
1937 ret = layout->textWidth(style->font, text+start, len);
1938 } else {
1939 int after = 0;
1940
1941 text += start;
1942 while (ispunct(text[after]))
1943 after++;
1944 if (text[after])
1945 after = layout->nextGlyph(text, after);
1946 if (after > len)
1947 after = len;
1948 str = layout->textToUpper(text, after);
1949 ret = layout->textWidth(style->font, str, strlen(str)) +
1950 layout->textWidth(style->font, text+after, len-after);
1951 }
1952 } else
1953 ret = layout->textWidth(style->font, text+start, len);
1954 break;
1955 }
1956
1957 if (str)
1958 free(str);
1959 }
1960
1961 return ret;
1962}
1963
1969void Textblock::calcTextSize (const char *text, size_t len,
1971 core::Requisition *size, bool isStart, bool isEnd)
1972{
1973 size->width = textWidth (text, 0, len, style, isStart, isEnd);
1974 size->ascent = style->font->ascent;
1975 size->descent = style->font->descent;
1976
1977 /*
1978 * For 'normal' line height, just use ascent and descent from font.
1979 * For absolute/percentage, line height is relative to font size, which
1980 * is (irritatingly) smaller than ascent+descent.
1981 */
1983 int height, leading;
1984 float factor = style->font->size;
1985
1986 factor /= (style->font->ascent + style->font->descent);
1987
1988 size->ascent = lout::misc::roundInt(size->ascent * factor);
1989 size->descent = lout::misc::roundInt(size->descent * factor);
1990
1991 /* TODO: The containing block's line-height property gives a minimum
1992 * height for the line boxes. (Even when it's set to 'normal', i.e.,
1993 * AUTO? Apparently.) Once all block elements make Textblocks or
1994 * something, this can be handled.
1995 */
1998 else
1999 height =
2001 style->lineHeight);
2002 leading = height - style->font->size;
2003
2004 size->ascent += leading / 2;
2005 size->descent += leading - (leading / 2);
2006 }
2007
2008 /* In case of a sub or super script we increase the word's height and
2009 * potentially the line's height.
2010 */
2012 int requiredDescent = style->font->descent + style->font->ascent / 3;
2013 size->descent = misc::max (size->descent, requiredDescent);
2014 } else if (style->valign == core::style::VALIGN_SUPER) {
2015 int requiredAscent = style->font->ascent + style->font->ascent / 2;
2016 size->ascent = misc::max (size->ascent, requiredAscent);
2017 }
2018}
2019
2024void Textblock::addText (const char *text, size_t len,
2026{
2027 DBG_OBJ_ENTER ("construct.word", 0, "addText", "..., %d, %p",
2028 (int)len, style);
2029
2030 // Count dividing characters.
2031 int numParts = 1;
2032
2033 for (const char *s = text; s; s = nextUtf8Char (s, text + len - s)) {
2034 int foundDiv = -1;
2035 for (int j = 0; foundDiv == -1 && j < NUM_DIV_CHARS; j++) {
2036 int lDiv = strlen (divChars[j].s);
2037 if (s <= text + len - lDiv) {
2038 if (memcmp (s, divChars[j].s, lDiv * sizeof (char)) == 0)
2039 foundDiv = j;
2040 }
2041 }
2042
2043 if (foundDiv != -1) {
2044 if (divChars[foundDiv].penaltyIndexLeft != -1)
2045 numParts ++;
2046 if (divChars[foundDiv].penaltyIndexRight != -1)
2047 numParts ++;
2048 }
2049 }
2050
2051 if (numParts == 1) {
2052 // Simple (and common) case: no dividing characters. May still
2053 // be hyphenated automatically.
2054 core::Requisition size;
2055 calcTextSize (text, len, style, &size, true, true);
2056 addText0 (text, len,
2058 style, &size);
2059
2060 //printf ("[%p] %d: added simple word: ", this, words->size() - 1);
2061 //printWordWithFlags (words->getLastRef());
2062 //printf ("\n");
2063 } else {
2064 PRINTF ("HYPHENATION: '");
2065 for (size_t i = 0; i < len; i++)
2066 PUTCHAR(text[i]);
2067 PRINTF ("', with %d parts\n", numParts);
2068
2069 // Store hyphen positions.
2070 int n = 0, totalLenCharRemoved = 0;
2071 int *partPenaltyIndex = new int[numParts - 1];
2072 int *partStart = new int[numParts];
2073 int *partEnd = new int[numParts];
2074 bool *charRemoved = new bool[numParts - 1];
2075 bool *canBeHyphenated = new bool[numParts + 1];
2076 bool *permDivChar = new bool[numParts - 1];
2077 bool *unbreakableForMinWidth = new bool[numParts - 1];
2078 canBeHyphenated[0] = canBeHyphenated[numParts] = true;
2079 partStart[0] = 0;
2080 partEnd[numParts - 1] = len;
2081
2082 for (const char *s = text; s; s = nextUtf8Char (s, text + len - s)) {
2083 int foundDiv = -1;
2084 for (int j = 0; foundDiv == -1 && j < NUM_DIV_CHARS; j++) {
2085 int lDiv = strlen (divChars[j].s);
2086 if (s <= text + len - lDiv) {
2087 if (memcmp (s, divChars[j].s, lDiv * sizeof (char)) == 0)
2088 foundDiv = j;
2089 }
2090 }
2091
2092 if (foundDiv != -1) {
2093 int lDiv = strlen (divChars[foundDiv].s);
2094
2095 if (divChars[foundDiv].charRemoved) {
2096 assert (divChars[foundDiv].penaltyIndexLeft != -1);
2097 assert (divChars[foundDiv].penaltyIndexRight == -1);
2098
2099 partPenaltyIndex[n] = divChars[foundDiv].penaltyIndexLeft;
2100 charRemoved[n] = true;
2101 permDivChar[n] = false;
2102 unbreakableForMinWidth[n] =
2104 canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated;
2105 partEnd[n] = s - text;
2106 partStart[n + 1] = s - text + lDiv;
2107 n++;
2108 totalLenCharRemoved += lDiv;
2109 } else {
2110 assert (divChars[foundDiv].penaltyIndexLeft != -1 ||
2111 divChars[foundDiv].penaltyIndexRight != -1);
2112
2113 if (divChars[foundDiv].penaltyIndexLeft != -1) {
2114 partPenaltyIndex[n] = divChars[foundDiv].penaltyIndexLeft;
2115 charRemoved[n] = false;
2116 permDivChar[n] = false;
2117 unbreakableForMinWidth[n] =
2119 canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated;
2120 partEnd[n] = s - text;
2121 partStart[n + 1] = s - text;
2122 n++;
2123 }
2124
2125 if (divChars[foundDiv].penaltyIndexRight != -1) {
2126 partPenaltyIndex[n] = divChars[foundDiv].penaltyIndexRight;
2127 charRemoved[n] = false;
2128 permDivChar[n] = true;
2129 unbreakableForMinWidth[n] =
2131 canBeHyphenated[n + 1] = divChars[foundDiv].canBeHyphenated;
2132 partEnd[n] = s - text + lDiv;
2133 partStart[n + 1] = s - text + lDiv;
2134 n++;
2135 }
2136 }
2137 }
2138 }
2139
2140 // Get text without removed characters, e. g. hyphens.
2141 const char *textWithoutHyphens;
2142 char *textWithoutHyphensBuf = new char[len - totalLenCharRemoved];
2143 int *breakPosWithoutHyphens;
2144 int *breakPosWithoutHyphensBuf = new int[numParts - 1];
2145
2146 if (totalLenCharRemoved == 0) {
2147 // No removed characters: take original arrays.
2148 textWithoutHyphens = text;
2149 // Ends are also break positions, except the last end, which
2150 // is superfluous, but does not harm (since arrays in C/C++
2151 // does not have an implicit length).
2152 breakPosWithoutHyphens = partEnd;
2153 } else {
2154 // Copy into special buffers.
2155 textWithoutHyphens = textWithoutHyphensBuf;
2156 breakPosWithoutHyphens = breakPosWithoutHyphensBuf;
2157
2158 int n = 0;
2159 for (int i = 0; i < numParts; i++) {
2160 memmove (textWithoutHyphensBuf + n, text + partStart[i],
2161 partEnd[i] - partStart[i]);
2162 n += partEnd[i] - partStart[i];
2163 if (i < numParts - 1)
2164 breakPosWithoutHyphensBuf[i] = n;
2165 }
2166 }
2167
2168 PRINTF("H... without hyphens: '");
2169 for (size_t i = 0; i < len - totalLenCharRemoved; i++)
2170 PUTCHAR(textWithoutHyphens[i]);
2171 PRINTF("'\n");
2172
2173 core::Requisition *wordSize = new core::Requisition[numParts];
2174 calcTextSizes (textWithoutHyphens, len - totalLenCharRemoved, style,
2175 numParts - 1, breakPosWithoutHyphens, wordSize);
2176
2177 // Finished!
2178 for (int i = 0; i < numParts; i++) {
2179 short flags = 0;
2180
2181 // If this parts adjoins at least one division characters,
2182 // for which canBeHyphenated is set to false (this is the
2183 // case for soft hyphens), do not hyphenate.
2184 if (canBeHyphenated[i] && canBeHyphenated[i + 1])
2186
2187 if(i < numParts - 1) {
2188 if (charRemoved[i])
2190
2191 if (permDivChar[i])
2193 if (unbreakableForMinWidth[i])
2195
2197 }
2198
2199 if (i == 0)
2201 if (i == numParts - 1)
2203
2204 addText0 (text + partStart[i], partEnd[i] - partStart[i],
2205 flags, style, &wordSize[i]);
2206
2207 //printf ("[%p] %d: added word part: ", this, words->size() - 1);
2208 //printWordWithFlags (words->getLastRef());
2209 //printf ("\n");
2210
2211 //PRINTF("H... [%d] '", i);
2212 //for (int j = partStart[i]; j < partEnd[i]; j++)
2213 // PUTCHAR(text[j]);
2214 //PRINTF("' added\n");
2215
2216 if(i < numParts - 1) {
2217 Word *word = words->getLastRef();
2218
2219 setBreakOption (word, style, penalties[partPenaltyIndex[i]][0],
2220 penalties[partPenaltyIndex[i]][1], false);
2221 DBG_SET_WORD (words->size () - 1);
2222
2223 if (charRemoved[i])
2224 // Currently, only unconditional hyphens (UTF-8:
2225 // "\xe2\x80\x90") can be used. See also drawWord, last
2226 // section "if (drawHyphen)".
2227 // Could be extended by adding respective members to
2228 // DivChar and Word.
2229 word->hyphenWidth =
2231 strlen (hyphenDrawChar));
2232
2233 accumulateWordData (words->size() - 1);
2235 }
2236 }
2237
2238 delete[] partPenaltyIndex;
2239 delete[] partStart;
2240 delete[] partEnd;
2241 delete[] charRemoved;
2242 delete[] canBeHyphenated;
2243 delete[] permDivChar;
2244 delete[] unbreakableForMinWidth;
2245 delete[] textWithoutHyphensBuf;
2246 delete[] breakPosWithoutHyphensBuf;
2247 delete[] wordSize;
2248 }
2249
2250 DBG_OBJ_LEAVE ();
2251}
2252
2253void Textblock::calcTextSizes (const char *text, size_t textLen,
2255 int numBreaks, int *breakPos,
2256 core::Requisition *wordSize)
2257{
2258 // The size of the last part is calculated in a simple way.
2259 int lastStart = breakPos[numBreaks - 1];
2260 calcTextSize (text + lastStart, textLen - lastStart, style,
2261 &wordSize[numBreaks], true, true);
2262
2263 PRINTF("H... [%d] '", numBreaks);
2264 for (size_t i = 0; i < textLen - lastStart; i++)
2265 PUTCHAR(text[i + lastStart]);
2266 PRINTF("' -> %d\n", wordSize[numBreaks].width);
2267
2268 // The rest is more complicated. See dw-line-breaking, section
2269 // "Hyphens".
2270 for (int i = numBreaks - 1; i >= 0; i--) {
2271 int start = (i == 0) ? 0 : breakPos[i - 1];
2272 calcTextSize (text + start, textLen - start, style, &wordSize[i],
2273 i == 0, i == numBreaks - 1);
2274
2275 PRINTF("H... [%d] '", i);
2276 for (size_t j = 0; j < textLen - start; j++)
2277 PUTCHAR(text[j + start]);
2278 PRINTF("' -> %d\n", wordSize[i].width);
2279
2280 for (int j = i + 1; j < numBreaks + 1; j++) {
2281 wordSize[i].width -= wordSize[j].width;
2282 PRINTF("H... - %d = %d\n", wordSize[j].width, wordSize[i].width);
2283 }
2284 }
2285}
2286
2291bool Textblock::calcSizeOfWidgetInFlow (int wordIndex, Widget *widget,
2292 core::Requisition *size)
2293{
2294 DBG_OBJ_ENTER ("resize", 0, "calcSizeOfWidgetInFlow", "%d, %p, ...",
2295 wordIndex, widget);
2296
2297 bool result, firstWordOfLine;
2298
2299 if (hasListitemValue)
2300 // For list items, the word #0 at the beginning (bullet, number ...) has
2301 // to be considered;
2302 firstWordOfLine = wordIndex == 1 ||
2303 (wordIndex > 0 &&
2304 words->getRef(wordIndex - 1)->content.type == core::Content::BREAK);
2305 else
2306 firstWordOfLine = wordIndex == 0 ||
2307 words->getRef(wordIndex - 1)->content.type == core::Content::BREAK;
2308
2309 DBG_OBJ_MSGF ("resize", 1, "firstWordOfLine = %s",
2310 boolToStr (firstWordOfLine));
2311
2312 if (firstWordOfLine &&
2313 (widget->getStyle()->display == core::style::DISPLAY_BLOCK ||
2314 widget->getStyle()->display == core::style::DISPLAY_LIST_ITEM ||
2315 widget->getStyle()->display == core::style::DISPLAY_TABLE)) {
2316 // pass positions
2317 DBG_OBJ_MSG ("resize", 1, "pass position");
2318 int lastWord = lines->empty () ? -1 : lines->getLastRef()->lastWord;
2319 assert (wordIndex > lastWord);
2320
2321 // The position passed to sizeRequest must be equivalent to the position
2322 // passed later to sizeAllocate. This is more complicated for widgets
2323 // which are centered or aligned to the right: here, we have to know the
2324 // width to calculate the horizontal position. Both are calculated in an
2325 // iterative way; initially, the left border is used (like for other,
2326 // simpler alignments).
2327
2328 // Since the child widget will regard floats, we do not have to include
2329 // floats when calculating left and right border.
2330
2331 // TODO Actually line1OffsetEff should be used instead of line1Offset, but
2332 // it may not initialized here. Anyway, since ignoreLine1OffsetSometimes
2333 // is not used, line1OffsetEff is always equal to line1Offset.
2334
2335 int leftBorder = boxOffsetX () + leftInnerPadding
2336 + (lines->size () == 0 ? line1Offset /* ...Eff, actually */ : 0);
2337 int rightBorder = boxRestWidth ();
2338
2339 int lastMargin, yLine = yOffsetOfLineToBeCreated (&lastMargin);
2340 int yRel = yLine - min (lastMargin, widget->getStyle()->margin.top);
2341
2342 DBG_OBJ_MSGF ("resize", 1,
2343 "leftBorder = %d + %d + (%d == 0 ? %d : 0) = %d, "
2344 "rightBorder = %d, yRel = %d - min (%d, %d) = %d",
2345 boxOffsetX (), leftInnerPadding , lines->size (),
2346 line1OffsetEff, leftBorder, rightBorder, yLine, lastMargin,
2347 widget->getStyle()->margin.top, yRel);
2348
2349 core::SizeParams childParams;
2350 DBG_OBJ_ASSOC_CHILD (&childParams);
2351
2352 int oldXRel = leftBorder;
2353
2354 sizeRequestParams.forChild (this, widget, oldXRel, yRel, &childParams);
2355 widget->sizeRequest (size, childParams.getNumPos (),
2356 childParams.getReferences (), childParams.getX (),
2357 childParams.getY ());
2358
2360
2361 while (true) {
2363
2364 int xRel;
2365
2366 switch(widget->getStyle()->textAlign) {
2368 case core::style::TEXT_ALIGN_STRING: // see comment in alignLine()
2369 case core::style::TEXT_ALIGN_JUSTIFY: // equivalent for only one word
2370 default: // compiler happiness
2371 xRel = leftBorder;
2372 break;
2373
2375 xRel = lineBreakWidth - rightBorder - size->width;
2376 break;
2377
2379 xRel =
2380 (leftBorder + lineBreakWidth - rightBorder - size->width) / 2;
2381 break;
2382 }
2383
2384 // Cf. Textblock::calcTextOffset().
2385 if (xRel < leftBorder)
2386 xRel = leftBorder;
2387
2388 DBG_OBJ_MSGF ("resize", 2, "xRel = %d, oldXRel = %d", xRel, oldXRel);
2389
2390 // Stop when the value of xRel has not changed during the last
2391 // iteration.
2392 if (xRel == oldXRel)
2393 break;
2394
2395 sizeRequestParams.forChild (this, widget, xRel, yRel, &childParams);
2396 widget->sizeRequest (size, childParams.getNumPos (),
2397 childParams.getReferences (), childParams.getX (),
2398 childParams.getY ());
2399
2400 oldXRel = xRel;
2401
2402 DBG_OBJ_MSG_END ();
2403 }
2404
2405 DBG_OBJ_MSG_END ();
2406
2407 result = true;
2408 } else {
2409 // do not pass positions (inline elements etc)
2410 DBG_OBJ_MSG ("resize", 1, "do not pass position");
2411 widget->sizeRequest (size);
2412 result = false;
2413 }
2414
2415 DBG_OBJ_LEAVE_VAL ("%s", boolToStr (result));
2416 return result;
2417}
2418
2420 int *yRef)
2421{
2422 if (reference == this) {
2423 if (xRef)
2424 *xRef = 0;
2425 if (yRef)
2426 *yRef = 0;
2427 return true;
2428 } else
2429 return sizeRequestParams.findReference (reference, xRef, yRef);
2430}
2431
2435void Textblock::addText0 (const char *text, size_t len, short flags,
2437{
2438 DBG_OBJ_ENTER ("construct.word", 0, "addText0",
2439 "..., %d, %s:%s:%s:%s:%s:%s:%s:%s, %p, %d * (%d + %d)",
2440 (int)len,
2441 (flags & Word::CAN_BE_HYPHENATED) ? "h?" : "--",
2442 (flags & Word::DIV_CHAR_AT_EOL) ? "de" : "--",
2443 (flags & Word::PERM_DIV_CHAR) ? "dp" : "--",
2444 (flags & Word::DRAW_AS_ONE_TEXT) ? "t1" : "--",
2445 (flags & Word::UNBREAKABLE_FOR_MIN_WIDTH) ? "um" : "--",
2446 (flags & Word::WORD_START) ? "st" : "--",
2447 (flags & Word::WORD_END) ? "en" : "--",
2448 (flags & Word::TOPLEFT_OF_LINE) ? "00" : "--",
2449 style, size->width, size->ascent, size->descent);
2450
2451 //printf("[%p] addText0 ('", this);
2452 //for (size_t i = 0; i < len; i++)
2453 // putchar(text[i]);
2454 //printf("', ");
2455 //printWordFlags (flags);
2456 //printf (", ...)\n");
2457
2458 Word *word = addWord (size->width, size->ascent, size->descent,
2459 flags, style);
2461 word->content.type = core::Content::TEXT;
2462 word->content.text = layout->textZone->strndup(text, len);
2463
2464 DBG_SET_WORD (words->size () - 1);
2465
2466 // The following debug message may be useful to identify the
2467 // different textblocks.
2468
2469 //if (words->size() == 1)
2470 // printf ("[%p] first word: '%s'\n", this, text);
2471
2472 processWord (words->size () - 1);
2473
2474 DBG_OBJ_LEAVE ();
2475}
2476
2481{
2482 DBG_OBJ_ENTER ("construct.word", 0, "addWidget", "%p, %p", widget, style);
2483
2484 /* We first assign -1 as parent_ref, since the call of widget->size_request
2485 * will otherwise let this Textblock be rewrapped from the beginning.
2486 * (parent_ref is actually undefined, but likely has the value 0.) At the,
2487 * end of this function, the correct value is assigned. */
2488 widget->parentRef = -1;
2489 DBG_OBJ_SET_NUM_O (widget, "parentRef", widget->parentRef);
2490
2491 widget->setStyle (style);
2492
2494
2495 if (testWidgetOutOfFlow (widget)) {
2496 int oofmIndex = getOOFMIndex (widget);
2497 DBG_OBJ_MSGF ("construct.word", 1, "ouf of flow: oofmIndex = %d (%s)",
2498 oofmIndex, OOFM_NAME[oofmIndex]);
2499
2500 widget->setParent (oofContainer[oofmIndex]);
2501 widget->setGenerator (this);
2502
2503 oof::OutOfFlowMgr *oofm = searchOutOfFlowMgr (oofmIndex);
2504 int oofmSubRef = oofm->addWidgetOOF (widget, this, words->size ());
2505 widget->parentRef = makeParentRefOOF (oofmIndex, oofmSubRef);
2506
2507 DBG_OBJ_MSGF ("construct.word", 1, "oofmSubRef = %d => parentRef = %d",
2508 oofmSubRef, widget->parentRef);
2509
2510 core::Requisition size;
2511 oofm->calcWidgetRefSize (widget, &size);
2512 Word *word = addWord (size.width, size.ascent, size.descent, 0, style);
2514 word->content.widgetReference = new core::WidgetReference (widget);
2516
2517 // After a out-of-flow reference, breaking is allowed. (This avoids some
2518 // problems with breaking near float definitions.)
2519 setBreakOption (word, style, 0, 0, false);
2520 } else {
2521 DBG_OBJ_MSG ("construct.word", 1, "in flow");
2522
2523 widget->setParent (this);
2524
2525 // TODO Replace (perhaps) later "textblock" by "OOF aware widget".
2526 if (widget->instanceOf (Textblock::CLASS_ID)) {
2527 for (int i = 0; i < NUM_OOFM; i++)
2528 searchOutOfFlowMgr(i)->addWidgetInFlow ((Textblock*)widget, this,
2529 words->size ());
2530 }
2531
2532 core::Requisition size;
2533 short flags = calcSizeOfWidgetInFlow (words->size (), widget, &size) ?
2535 Word *word =
2536 addWord (size.width, size.ascent, size.descent, flags, style);
2538 word->content.widget = widget;
2539 }
2540
2541 DBG_SET_WORD (words->size () - 1);
2542
2543 processWord (words->size () - 1);
2544 //DBG_OBJ_SET_NUM (word->content.widget, "parent_ref",
2545 // word->content.widget->parent_ref);
2546
2547 //DEBUG_MSG(DEBUG_REWRAP_LEVEL,
2548 // "Assigning parent_ref = %d to added word %d, "
2549 // "in page with %d word(s)\n",
2550 // lines->size () - 1, words->size() - 1, words->size());
2551
2552 DBG_OBJ_LEAVE ();
2553}
2554
2563{
2564 DBG_OBJ_ENTER ("construct.word", 0, "addAnchor", "\"%s\", %p", name, style);
2565
2566 char *copy;
2567 int y;
2568 bool result;
2569
2570 // Since an anchor does not take any space, it is safe to call
2571 // addAnchor already here.
2572 if (wasAllocated ()) {
2573 if (lines->size () == 0)
2574 y = allocation.y;
2575 else
2576 y = allocation.y + lineYOffsetWidget (lines->size () - 1);
2577 copy = Widget::addAnchor (name, y);
2578 } else
2579 copy = Widget::addAnchor (name);
2580
2581 if (copy == NULL)
2586 result = false;
2587 else {
2588 Anchor *anchor;
2589
2590 anchors->increase();
2591 anchor = anchors->getRef(anchors->size() - 1);
2592 anchor->name = copy;
2593 anchor->wordIndex = words->size();
2594 result = true;
2595 }
2596
2597 DBG_OBJ_LEAVE_VAL ("%s", boolToStr(result));
2598 return result;
2599}
2600
2601
2606{
2607 DBG_OBJ_ENTER ("construct.word", 0, "addSpace", "%p", style);
2608
2609 int wordIndex = words->size () - 1;
2610 if (wordIndex >= 0) {
2611 fillSpace (wordIndex, style);
2612 DBG_SET_WORD (wordIndex);
2613 accumulateWordData (wordIndex);
2615 }
2616
2617 DBG_OBJ_LEAVE ();
2618}
2619
2627{
2628 DBG_OBJ_ENTER ("construct.word", 0, "addBreakOption", "%p, %s",
2629 style, forceBreak ? "true" : "false");
2630
2631 int wordIndex = words->size () - 1;
2632 if (wordIndex >= 0) {
2633 setBreakOption (words->getRef(wordIndex), style, 0, 0, forceBreak);
2634 DBG_SET_WORD (wordIndex);
2635 // Call of accumulateWordData() is not needed here.
2637 }
2638
2639 DBG_OBJ_LEAVE ();
2640}
2641
2643{
2644 DBG_OBJ_ENTER ("construct.word", 0, "fillSpace", "%d, ...", wordNo);
2645
2646 DBG_OBJ_MSGF ("construct.word", 1, "style.white-space = %s",
2650 "nowrap"
2652 "pre-wrap"
2654 "pre-line" : "???");
2655
2656 // Old comment:
2657 //
2658 // According to
2659 // http://www.w3.org/TR/CSS2/text.html#white-space-model: "line
2660 // breaking opportunities are determined based on the text
2661 // prior to the white space collapsing steps".
2662 //
2663 // So we call addBreakOption () for each Textblock::addSpace ()
2664 // call. This is important e.g. to be able to break between
2665 // foo and bar in: <span style="white-space:nowrap">foo </span>
2666 // bar
2667 //
2668 // TODO: Re-evaluate again.
2669
2670 Word *word = words->getRef (wordNo);
2671
2672 // TODO: This line does not work: addBreakOption (word, style);
2673
2674 if (// Do not override a previously set break penalty:
2675 !word->content.space &&
2676 // OOF references are considered specially, and must not have a space:
2677 word->content.type != core::Content::WIDGET_OOF_REF) {
2678 setBreakOption (word, style, 0, 0, false);
2679
2680 word->content.space = true;
2681 word->origSpace = word->effSpace =
2683
2684 removeSpaceImgRenderer (wordNo);
2685
2686 word->spaceStyle->unref ();
2687 word->spaceStyle = style;
2688 style->ref ();
2689
2690 setSpaceImgRenderer (wordNo);
2691 }
2692
2693 DBG_OBJ_LEAVE ();
2694}
2695
2702 int breakPenalty1, int breakPenalty2,
2703 bool forceBreak)
2704{
2705 DBG_OBJ_ENTER ("construct.word", 0, "setBreakOption", "..., %d, %d, %s",
2706 breakPenalty1, breakPenalty2, forceBreak ? "true" : "false");
2707
2708 // TODO: lineMustBeBroken should be independent of the penalty
2709 // index? Otherwise, examine the last line.
2710 if (!word->badnessAndPenalty.lineMustBeBroken(0)) {
2711 if (forceBreak || isBreakAllowed (style))
2712 word->badnessAndPenalty.setPenalties (breakPenalty1, breakPenalty2);
2713 else
2715 }
2716
2717 DBG_OBJ_LEAVE ();
2718}
2719
2721{
2722 switch (style->whiteSpace) {
2726 return true;
2727
2730 return false;
2731
2732 default:
2733 // compiler happiness
2735 return false;
2736 }
2737}
2738
2739
2744{
2745 DBG_OBJ_ENTER ("construct.word", 0, "addParbreak", "%d, %p",
2746 space, style);
2747 DBG_OBJ_MSG ("construct.word", 0,
2748 "<i>No nesting! Strack trace may be incomplete.</i>");
2749 DBG_OBJ_LEAVE ();
2750
2751 Word *word;
2752
2753 /* A break may not be the first word of a page, or directly after
2754 the bullet/number (which is the first word) in a list item. (See
2755 also comment in sizeRequest.) */
2756 if (words->size () == 0 ||
2757 (hasListitemValue && words->size () == 1)) {
2758 /* This is a bit hackish: If a break is added as the
2759 first/second word of a page, and the parent widget is also a
2760 Textblock, and there is a break before -- this is the case when
2761 a widget is used as a text box (lists, blockquotes, list
2762 items etc) -- then we simply adjust the break before, in a
2763 way that the space is in any case visible. */
2764 /* Find the widget where to adjust the breakSpace. (Only
2765 consider normal flow, no floats etc.) */
2766 for (Widget *widget = this;
2767 widget->getParent() != NULL &&
2768 widget->getParent()->instanceOf (Textblock::CLASS_ID) &&
2769 !isWidgetOOF (widget);
2770 widget = widget->getParent ()) {
2771 Textblock *textblock2 = (Textblock*)widget->getParent ();
2772 int index = textblock2->hasListitemValue ? 1 : 0;
2773 bool isfirst = (textblock2->words->getRef(index)->content.type
2775 && textblock2->words->getRef(index)->content.widget
2776 == widget);
2777 if (!isfirst) {
2778 /* The text block we searched for has been found. */
2779 Word *word2;
2780 int lineno = getWidgetInFlowSubRef (widget);
2781
2782 if (lineno > 0 &&
2783 (word2 =
2784 textblock2->words->getRef(textblock2->lines
2785 ->getRef(lineno - 1)->firstWord)) &&
2786 word2->content.type == core::Content::BREAK) {
2787 if (word2->content.breakSpace < space) {
2788 word2->content.breakSpace = space;
2789 textblock2->queueResize (makeParentRefInFlow (lineno), false);
2790 textblock2->mustQueueResize = false;
2791 DBG_OBJ_SET_BOOL_O (textblock2, "mustQueueResize",
2792 textblock2->mustQueueResize);
2793 }
2794 }
2795 return;
2796 }
2797 /* Otherwise continue to examine parents. */
2798 }
2799
2800 /* Return in any case. */
2801 return;
2802 }
2803
2804 /* Another break before? */
2805 if ((word = words->getRef(words->size () - 1)) &&
2807 Line *lastLine = lines->getRef (lines->size () - 1);
2808
2809 word->content.breakSpace =
2810 misc::max (word->content.breakSpace, space);
2811 lastLine->breakSpace =
2813 lastLine->marginDescent - lastLine->borderDescent,
2814 lastLine->breakSpace);
2815 return;
2816 }
2817
2818 word = addWord (0, 0, 0, 0, style);
2822 word->content.breakSpace = space;
2823
2824 DBG_SET_WORD (words->size () - 1);
2825
2826 breakAdded ();
2827 processWord (words->size () - 1);
2828}
2829
2830/*
2831 * Cause a line break.
2832 */
2834{
2835 DBG_OBJ_ENTER ("construct.word", 0, "addLinebreak", "%p", style);
2836
2837 Word *word;
2838
2839 if (words->size () == 0 ||
2840 words->getRef(words->size () - 1)->content.type == core::Content::BREAK)
2841 // An <BR> in an empty line gets the height of the current font
2842 // (why would someone else place it here?), ...
2843 word =
2845 else
2846 // ... otherwise, it has no size (and does not enlarge the line).
2847 word = addWord (0, 0, 0, 0, style);
2848
2850
2853 word->content.breakSpace = 0;
2854
2855 DBG_SET_WORD (words->size () - 1);
2856
2857 breakAdded ();
2858 processWord (words->size () - 1);
2859
2860 DBG_OBJ_LEAVE ();
2861}
2862
2867{
2868 assert (words->size () >= 1);
2869 assert (words->getRef(words->size () - 1)->content.type
2871
2872 // Any space before is removed. It is not used; on the other hand,
2873 // this snippet (an example from a real-world debugging session)
2874 // would cause problems:
2875 //
2876 // <input style="width: 100%" .../>
2877 // <button ...>...</button>
2878 //
2879 // (Notice the space between <input> and <button>, and also that
2880 // the HTML parser will insert a BREAK between them.) The <input>
2881 // would be given the available width ("width: 100%"), but the
2882 // actual width (Word::totalWidth) would include the space, so that
2883 // the width of the line is larger than the available width.
2884
2885 if (words->size () >= 2)
2886 words->getRef(words->size () - 2)->origSpace =
2887 words->getRef(words->size () - 2)->effSpace = 0;
2888}
2889
2892 *context)
2893{
2894 DBG_OBJ_ENTER ("events", 0, "Textblock::getWidgetAtPointLevel", "%d, %d, %s",
2895 x, y, stackingLevelText (level));
2896
2897 Widget *widgetAtPoint = NULL;
2898
2899 switch (level) {
2900 case SL_IN_FLOW:
2901 {
2902 int lineIndex = findLineIndexWhenAllocated (y - allocation.y);
2903
2904 if (lineIndex >= 0 && lineIndex < lines->size ()) {
2905 Line *line = lines->getRef (lineIndex);
2906
2907 for (int wordIndex = line->lastWord;
2908 widgetAtPoint == NULL && wordIndex >= line->firstWord;
2909 wordIndex--) {
2910 Word *word = words->getRef (wordIndex);
2913 (word->content.widget))
2914 widgetAtPoint =
2915 word->content.widget->getWidgetAtPoint (x, y, context);
2916 }
2917 }
2918 }
2919 break;
2920
2921 case SL_OOF_REF:
2922 // TODO Inefficient. Perhaps store OOF references in seperate
2923 // (much smaller!) list.
2924 for (int oofmIndex = NUM_OOFM; widgetAtPoint == NULL && oofmIndex >= 0;
2925 oofmIndex--) {
2926 for (int wordIndex = words->size () - 1;
2927 widgetAtPoint == NULL && wordIndex >= 0; wordIndex--) {
2928 Word *word = words->getRef (wordIndex);
2931 == oofmIndex &&
2933 ->widget))
2934 widgetAtPoint =
2936 ->getWidgetAtPointInterrupted (x, y, context);
2937 }
2938 }
2939 break;
2940
2941 default:
2942 widgetAtPoint =
2943 OOFAwareWidget::getWidgetAtPointLevel (x, y, level, context);
2944 break;
2945 }
2946
2947 DBG_OBJ_LEAVE_VAL ("%p", widgetAtPoint);
2948 return widgetAtPoint;
2949}
2950
2956{
2957 if (lines->size() > 0) {
2958 Widget *parent;
2959 Line *lastLine = lines->getRef (lines->size () - 1);
2960
2961 if (lastLine->breakSpace != 0 && (parent = getParent()) &&
2964 Textblock *textblock2 = (Textblock*) parent;
2965 textblock2->addParbreak(lastLine->breakSpace, style);
2966 }
2967 }
2968}
2969
2970/*
2971 * Any words added by addWord() are not immediately (queued to
2972 * be) drawn, instead, this function must be called. This saves some
2973 * calls to queueResize().
2974 *
2975 */
2977{
2978 DBG_OBJ_ENTER0 ("resize", 0, "flush");
2979
2980 if (mustQueueResize) {
2981 DBG_OBJ_MSG ("resize", 0, "mustQueueResize set");
2982
2983 queueResize (-1, true);
2984 mustQueueResize = false;
2985 DBG_OBJ_SET_BOOL ("mustQueueResize", mustQueueResize);
2986 }
2987
2988 DBG_OBJ_LEAVE ();
2989}
2990
2991
2992// next: Dw_page_find_word
2993
2994void Textblock::changeLinkColor (int link, int newColor)
2995{
2996 for (int lineIndex = 0; lineIndex < lines->size(); lineIndex++) {
2997 bool changed = false;
2998 Line *line = lines->getRef (lineIndex);
2999 int wordIdx;
3000
3001 for (wordIdx = line->firstWord; wordIdx <= line->lastWord; wordIdx++){
3002 Word *word = words->getRef(wordIdx);
3003
3004 if (word->style->x_link == link) {
3005 core::style::StyleAttrs styleAttrs;
3006
3007 switch (word->content.type) {
3009 { core::style::Style *old_style = word->style;
3010 styleAttrs = *old_style;
3012 newColor);
3013 word->style = core::style::Style::create (&styleAttrs);
3014 old_style->unref();
3015 old_style = word->spaceStyle;
3016 styleAttrs = *old_style;
3018 newColor);
3019 word->spaceStyle = core::style::Style::create(&styleAttrs);
3020 old_style->unref();
3021 break;
3022 }
3024 { core::Widget *widget = word->content.widget;
3025 styleAttrs = *widget->getStyle();
3027 newColor);
3028 styleAttrs.setBorderColor(
3030 widget->setStyle(core::style::Style::create (&styleAttrs));
3031 break;
3032 }
3033 default:
3034 break;
3035 }
3036 changed = true;
3037 }
3038 }
3039 if (changed)
3041 line->borderAscent + line->borderDescent);
3042 }
3043}
3044
3046 bool includeFirstSpace, bool includeLastSpace)
3047{
3048}
3049
3050void Textblock::queueDrawRange (int index1, int index2)
3051{
3052 DBG_OBJ_ENTER ("draw", 0, "queueDrawRange", "%d, %d", index1, index2);
3053
3054 int from = misc::min (index1, index2);
3055 int to = misc::max (index1, index2);
3056
3057 from = misc::min (from, words->size () - 1);
3058 from = misc::max (from, 0);
3059 to = misc::min (to, words->size () - 1);
3060 to = misc::max (to, 0);
3061
3062 int line1idx = findLineOfWord (from);
3063 int line2idx = findLineOfWord (to);
3064
3065 if (line1idx >= 0 && line2idx >= 0) {
3066 Line *line1 = lines->getRef (line1idx),
3067 *line2 = lines->getRef (line2idx);
3068 int y = lineYOffsetWidget (line1) + line1->borderAscent -
3069 line1->contentAscent;
3070 int h = lineYOffsetWidget (line2) + line2->borderAscent +
3071 line2->contentDescent - y;
3072
3073 queueDrawArea (0, y, allocation.width, h);
3074 }
3075
3076 DBG_OBJ_LEAVE ();
3077}
3078
3080{
3081 DBG_OBJ_ENTER ("resize", 0, "updateReference", "%d", ref);
3082
3083 // Only `queueResize` when there're words or float clearance
3084 // (float clearance may change `extraSpace.top`).
3085 if (words->size () > 0 || getStyle()->clear != core::style::CLEAR_NONE)
3086 queueResize (ref, false);
3087
3088 DBG_OBJ_LEAVE ();
3089}
3090
3091void Textblock::widgetRefSizeChanged (int externalIndex)
3092{
3093 int lineNo = findLineOfWord (externalIndex);
3094 if (lineNo >= 0 && lineNo < lines->size ())
3095 queueResize (makeParentRefInFlow (lineNo), true);
3096}
3097
3099{
3100 DBG_OBJ_ENTER ("resize", 0, "oofSizeChanged", "%s",
3101 extremesChanged ? "true" : "false");
3103
3104 // See Textblock::getAvailWidthOfChild(): Extremes changes may become also
3105 // relevant for the children, under certain conditions:
3108
3109 DBG_OBJ_LEAVE ();
3110}
3111
3112int Textblock::getGeneratorX (int oofmIndex)
3113{
3114 DBG_OBJ_ENTER ("resize", 0, "Textblock::getGeneratorX", "%d", oofmIndex);
3115
3116 int x, xRef;
3117 if (findSizeRequestReference (oofmIndex, &xRef, NULL))
3118 x = xRef;
3119 else {
3120 // Only called for floats, so this should not happen:
3122 x = 0;
3123 }
3124
3125 DBG_OBJ_LEAVE_VAL ("%d", x);
3126 return x;
3127}
3128
3129int Textblock::getGeneratorY (int oofmIndex)
3130{
3131 DBG_OBJ_ENTER ("resize", 0, "Textblock::getGeneratorY", "%d", oofmIndex);
3132
3133 int yRef, y;
3134 if (findSizeRequestReference (oofmIndex, NULL, &yRef))
3135 y = yRef;
3136 else {
3137 // Only called for floats, so this should not happen:
3139 y = 0;
3140 }
3141
3142 DBG_OBJ_LEAVE_VAL ("%d", y);
3143 return y;
3144}
3145
3147{
3148 DBG_OBJ_ENTER ("resize", 0, "Textblock::getGeneratorRest", "%d", oofmIndex);
3149
3150 int xRef, rest;
3152
3153 if (container != NULL && findSizeRequestReference (container, &xRef, NULL))
3154 rest = container->getGeneratorWidth () - (xRef + getGeneratorWidth ());
3155 else {
3156 // Only callend for floats, so this should not happen:
3158 rest = 0;
3159 }
3160
3161 DBG_OBJ_LEAVE_VAL ("%d", rest);
3162 return rest;
3163}
3164
3166{
3167 DBG_OBJ_ENTER0 ("resize", 0, "Textblock::getGeneratorWidth");
3168
3169 // Cf. sizeRequestImpl.
3170 if (usesMaxGeneratorWidth ()) {
3172 return lineBreakWidth;
3173 } else {
3174 // In some cases (especially when called from sizeRequest for an
3175 // ancestor), the value is not up to date, since content from children is
3176 // not yet added to lines. Moreover, this leads to inconsistencies between
3177 // this widget and ancestors (as in Textblock::getGeneratorRest). For this
3178 // reason, the children are examined recursively.
3179 //
3180 // Test case:
3181 //
3182 // <div style="float:left">
3183 // <div div style="float:right">float</div>
3184 // <div>abcdefghijkl mnopqrstuvwx</div>
3185 // </div>
3186
3187 int wChild = 0;
3188 int firstWordAfterLastLine =
3189 lines->size() > 0 ? lines->getLastRef()->lastWord + 1 : 0;
3190 for (int i = firstWordAfterLastLine; i < words->size(); i++) {
3191 Word *word = words->getRef(i);
3192 int xRel;
3193 // We only examine instances of dw::Textblock, since they are relevant
3194 // for floats, for which this method is only called.
3197 Textblock *tbChild = (Textblock*)word->content.widget;
3198 if(tbChild->findSizeRequestReference(this, &xRel, NULL))
3199 wChild = max(wChild, xRel + tbChild->getGeneratorWidth());
3200 }
3201 }
3202
3203 DBG_OBJ_MSGF ("resize", 1, "wChild = %d", wChild);
3204
3205 int w0 = lines->size () > 0 ? lines->getLastRef()->maxLineWidth : 0;
3206 DBG_OBJ_MSGF ("resize", 1, "w0 = %d", w0);
3207 int wThis = min(w0 + leftInnerPadding + boxDiffWidth (), lineBreakWidth);
3208 DBG_OBJ_MSGF ("resize", 1, "wThis = min(%d + %d + %d, %d) = %d",
3210 wThis);
3211 int w = max(wThis, wChild);
3212 DBG_OBJ_LEAVE_VAL ("max(%d, %d) = %d", wThis, wChild, w);
3213 return w;
3214 }
3215}
3216
3218{
3219 DBG_OBJ_ENTER0 ("resize", 0, "Textblock::getMaxGeneratorWidth");
3221 return lineBreakWidth;
3222}
3223
3225{
3226 DBG_OBJ_ENTER0 ("resize", 0, "usesMaxGeneratorWidth");
3227
3228 bool result;
3229 if (treatAsInline) {
3230 DBG_OBJ_MSG ("resize", 1, "treatAsInline set");
3231 result = false;
3232 } else {
3233 bool toplevel = getParent () == NULL,
3235 vloat = testWidgetFloat (this),
3236 abspos = testWidgetAbsolutelyPositioned (this),
3237 fixpos = testWidgetFixedlyPositioned (this);
3238 DBG_OBJ_MSGF("resize", 1,
3239 "toplevel: %s, block: %s, float: %s, abspos: %s, fixpos: %s",
3240 boolToStr(toplevel), boolToStr(block), boolToStr(vloat),
3241 boolToStr(abspos), boolToStr(fixpos));
3242
3243 // In detail, this depends on what the respective OOFM does with the
3244 // child widget:
3245 result = toplevel || (block && !(vloat || abspos || fixpos));
3246 }
3247
3248 DBG_OBJ_LEAVE_VAL ("%s", boolToStr(result));
3249 return result;
3250}
3251
3253{
3254 return true;
3255}
3256
3258{
3259 return true;
3260}
3261
3266
3268{
3269 // Can also be used for a line not yet existing.
3270 int firstWord = lineNo == 0 ? 0 : lines->getRef(lineNo - 1)->lastWord + 1;
3271 int lastWord = lineNo < lines->size() ?
3272 lines->getRef(lineNo)->lastWord : words->size() - 1;
3273 return getWidgetRegardingBorderForLine (firstWord, lastWord);
3274}
3275
3277 int lastWord)
3278{
3279 DBG_OBJ_ENTER ("resize", 0, "getWidgetRegardingBorderForLine", "%d, %d",
3280 firstWord, lastWord);
3281 DBG_OBJ_MSGF ("resize", 1, "words.size = %d", words->size ());
3282
3283 RegardingBorder *widgetRegardingBorder = NULL;
3284
3285 if (firstWord < words->size ()) {
3286 // Any instance of a subclass of WidgetRegardingBorder is always
3287 // between two line breaks, and so the first word of the line.
3288 Word *word = words->getRef (firstWord);
3289
3290 DBG_MSG_WORD ("resize", 1, "<i>first word:</i> ", firstWord, "");
3291
3293 Widget *widget = word->content.widget;
3294 if (widget->instanceOf (RegardingBorder::CLASS_ID) &&
3295 // Exclude cases where a textblock constitutes a new floats
3296 // container.
3297 !isOOFContainer (widget, OOFM_FLOATS))
3298 widgetRegardingBorder = (RegardingBorder*)widget;
3299 }
3300 }
3301
3302 DBG_OBJ_LEAVE_VAL ("%p", widgetRegardingBorder);
3303 return widgetRegardingBorder;
3304}
3305
3310{
3311 // This method does not return an exact result: the position of the
3312 // new line, which does not yet exist, cannot be calculated, since
3313 // the top margin of the new line (which collapses either with the
3314 // top margin of the textblock widget, or the bottom margin of the
3315 // last line) must be taken into account. However, this method is
3316 // only called for positioning floats; here, a slight incorrectness
3317 // does not cause real harm.
3318
3319 // (Similar applies to the line *height*, which calculated in an
3320 // iterative way; see wrapWordInFlow. Using the same approach for
3321 // the *position* is possible, but not worth the increased
3322 // complexity.)
3323
3324 DBG_OBJ_ENTER0 ("line.yoffset", 0, "yOffsetOfLineToBeCreated");
3325
3326 int result;
3327
3328 if (lines->size () == 0) {
3329 result = calcVerticalBorder (getStyle()->padding.top,
3330 getStyle()->borderWidth.top + extraSpace.top,
3331 getStyle()->margin.top, 0, 0);
3332 if (lastMargin)
3333 *lastMargin = getStyle()->margin.top;
3334 } else {
3335 Line *firstLine = lines->getRef (0), *lastLine = lines->getLastRef ();
3336 result = calcVerticalBorder (getStyle()->padding.top,
3337 getStyle()->borderWidth.top,
3338 getStyle()->margin.top + extraSpace.top,
3339 firstLine->borderAscent,
3340 firstLine->marginAscent)
3341 - firstLine->borderAscent + lastLine->top + lastLine->totalHeight (0);
3342 if (lastMargin)
3343 *lastMargin = lastLine->marginDescent - lastLine->borderDescent;
3344 }
3345
3346 if (lastMargin)
3347 DBG_OBJ_LEAVE_VAL ("%d, %d", result, *lastMargin);
3348 else
3349 DBG_OBJ_LEAVE_VAL ("%d", result);
3350
3351 return result;
3352}
3353
3358{
3359 // Similar applies (regarding exactness) as to yOffsetOfLineToBeCreated.
3360
3361 DBG_OBJ_ENTER0 ("line.yoffset", 0, "yOffsetOfLineToBeCreated");
3362
3363 int result;
3364
3365 Line *firstLine = lines->getRef (0);
3366 result = calcVerticalBorder (getStyle()->padding.top,
3367 getStyle()->borderWidth.top,
3368 getStyle()->margin.top + extraSpace.top,
3369 firstLine->borderAscent,
3370 firstLine->marginAscent)
3371 - firstLine->borderAscent + line->top;
3372
3373 DBG_OBJ_LEAVE_VAL ("%d", result);
3374 return result;
3375}
3376
3377} // 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
struct dw::Textblock::@28 hlEnd[core::HIGHLIGHT_NUM_LAYERS]
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
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...
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.
struct dw::Textblock::@28 hlStart[core::HIGHLIGHT_NUM_LAYERS]
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:44
virtual void setStyle(style::Style *style)
Change the style of a widget.
Definition widget.cc:1233
void setGenerator(Widget *generator)
Definition widget.hh:466
Allocation * getAllocation()
Definition widget.hh:470
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:581
Extremes extremes
Analogue to dw::core::Widget::requisition.
Definition widget.hh:166
Layout * layout
Definition widget.hh:209
Widget * container
The containing widget, equivalent to the "containing block" defined by CSS.
Definition widget.hh:146
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:203
virtual void draw(View *view, Rectangle *area, DrawingContext *context)=0
Area is given in widget coordinates.
void setButtonSensitive(bool buttonSensitive)
Definition widget.cc:1485
Widget * getParent()
Definition widget.hh:573
int boxDiffWidth()
Definition widget.hh:481
int parentRef
This value is defined by the parent widget, and used for incremential resizing.
Definition widget.hh:195
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:468
Requisition requisition
Size_request() stores the result of the last call of size_request_impl().
Definition widget.hh:160
Widget * getWidgetAtPointInterrupted(int x, int y, GettingWidgetAtPointContext *context)
Definition widget.cc:222
style::Box extraSpace
Space around the margin box.
Definition widget.hh:219
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:412
void setCursor(style::Cursor cursor)
Definition widget.hh:397
bool extremesQueued()
Definition widget.hh:456
bool extremesChanged()
Definition widget.hh:460
void changeAnchor(char *name, int y)
Definition widget.hh:389
void setParent(Widget *parent)
Definition widget.cc:231
int boxRestWidth()
Definition widget.hh:479
int boxRestHeight()
Definition widget.hh:484
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:127
style::Style * style
Definition widget.hh:150
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:461
void removeAnchor(char *name)
Definition widget.hh:392
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:1388
static Color * create(Layout *layout, int color)
Definition style.cc:529
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:679
#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:2027
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:20
T max(T a, T b)
Definition misc.hh:21
int roundInt(double d)
Definition misc.hh:62
void assertNotReached()
Definition misc.hh:36
const char * boolToStr(bool b)
Definition misc.hh:88
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
@ 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
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
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(...)
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