aboutsummaryrefslogtreecommitdiff
path: root/dw/textblock.hh
diff options
context:
space:
mode:
Diffstat (limited to 'dw/textblock.hh')
-rw-r--r--dw/textblock.hh244
1 files changed, 212 insertions, 32 deletions
diff --git a/dw/textblock.hh b/dw/textblock.hh
index ea7795b8..8d8f91cc 100644
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -1,18 +1,29 @@
#ifndef __DW_TEXTBLOCK_HH__
#define __DW_TEXTBLOCK_HH__
+#include <limits.h>
+
#include "core.hh"
#include "../lout/misc.hh"
+// These were used when improved line breaking and hyphenation were
+// implemented. Should be cleaned up; perhaps reactivate RTFL again.
+#define PRINTF(fmt, ...)
+#define PUTCHAR(ch)
+
namespace dw {
/**
* \brief A Widget for rendering text blocks, i.e. paragraphs or sequences
* of paragraphs.
*
- * <strong>Important Note:</strong>: This documentation is out of date, since
- * floats have been implementet. Will be updated and extended soon.
- *
+ * <div style="border: 2px solid #ffff00; margin-top: 0.5em;
+ * margin-bottom: 0.5em; padding: 0.5em 1em; background-color:
+ * #ffffe0"><b>Info:</b> The recent changes (line breaking and
+ * hyphenation on one hand, floats on the other hand) have not yet
+ * been incorporated into this documentation. See \ref
+ * dw-line-breaking and \ref dw-special-textflow.</div>
+ *
* <h3>Signals</h3>
*
* dw::Textblock uses the signals defined in
@@ -134,6 +145,76 @@ namespace dw {
class Textblock: public core::Widget
{
private:
+ // Hint: the following is somewhat chaotic, as a result of the merge
+ // of dillo_hyphen and dillo_floats
+
+ // Part 1 -- Line-Breaking and Hyphenation
+
+ /**
+ * This class encapsulates the badness/penalty calculation, and so
+ * (i) makes changes (hopefully) simpler, and (ii) hides the
+ * integer arithmetics (floating point arithmetics avoided for
+ * performance reasons). Unfortunately, the value range of the
+ * badness is not well defined, so fiddling with the penalties is a
+ * bit difficult.
+ */
+ class BadnessAndPenalty
+ {
+ private:
+ enum { NOT_STRETCHABLE, QUITE_LOOSE, BADNESS_VALUE, TOO_TIGHT }
+ badnessState;
+ enum { FORCE_BREAK, PROHIBIT_BREAK, PENALTY_VALUE } penaltyState;
+ int ratio; // ratio is only defined when badness is defined
+ int badness, penalty;
+
+ // for debugging:
+ int totalWidth, idealWidth, totalStretchability, totalShrinkability;
+
+ // "Infinity levels" are used to represent very large numbers,
+ // including "quasi-infinite" numbers. A couple of infinity
+ // level and number can be mathematically represented as
+ //
+ // number * N ^ (infinity level)
+ //
+ // where N is a number which is large enough. Practically,
+ // infinity levels are used to circumvent limited ranges for
+ // integer numbers.
+
+ // Here, all infinity levels have got special meanings.
+ enum {
+ INF_VALUE = 0, /* simple values */
+ INF_LARGE, /* large values, like QUITE_LOOSE */
+ INF_NOT_STRETCHABLE, /* reserved for NOT_STRECTHABLE */
+ INF_PENALTIES, /* used for penalties */
+ INF_TOO_TIGHT, /* used for lines, which are too tight;
+ that this is the last value means
+ that lines, which are too tight, are
+ regarded as the worst case */
+ INF_MAX = INF_TOO_TIGHT
+ };
+
+ int badnessValue (int infLevel);
+ int penaltyValue (int infLevel);
+
+ public:
+ void calcBadness (int totalWidth, int idealWidth,
+ int totalStretchability, int totalShrinkability);
+ void setPenalty (int penalty);
+ void setPenaltyProhibitBreak ();
+ void setPenaltyForceBreak ();
+
+ bool lineLoose ();
+ bool lineTight ();
+ bool lineTooTight ();
+ bool lineMustBeBroken ();
+ bool lineCanBeBroken ();
+ int compareTo (BadnessAndPenalty *other);
+
+ void print ();
+ };
+
+ // Part 2 -- Floats
+
Textblock *containingBox;
class FloatSide
@@ -192,8 +273,19 @@ private:
};
FloatSide *leftFloatSide, *rightFloatSide;
-
+
+ // End of merge chaos.
+
protected:
+ enum {
+ /**
+ * The penalty for hyphens, multiplied with 100. So, 100 means
+ * 1.0. See dw::Textblock::BadnessAndPenalty::setPenalty for
+ * more details.
+ */
+ HYPHEN_BREAK = 100
+ };
+
struct Line
{
int firstWord; /* first word's index in word vector */
@@ -209,17 +301,35 @@ protected:
* widgets within this line. */
int marginDescent;
- /* The following members contain accumulated values, from the top
- * down to the line before. */
- int maxLineWidth; /* maximum of all line widths */
- int maxWordMin; /* maximum of all word minima */
- int maxParMax; /* maximum of all paragraph maxima */
- int parMin; /* the minimal total width down from the last
- * paragraph start, to the *beginning* of the
- * line */
- int parMax; /* the maximal total width down from the last
- * paragraph start, to the *beginning* of the
- * line */
+ /* The following members contain accumulated values, from the
+ * top down to this line. Please notice a change: until
+ * recently, the values were accumulated up to the last line,
+ * not this line.
+ *
+ * Also, keep in mind that at the end of a line, the space of
+ * the last word is ignored, but instead, the hyphen width must
+ * be considered.*/
+
+ int maxLineWidth; /* Maximum of all line widths, including this
+ * line. Does not include the last space, but
+ * the last hyphen width. */
+ int maxParMin; /* Maximum of all paragraph minima, including
+ * this line. */
+ int maxParMax; /* Maximum of all paragraph maxima. This line
+ * is only included, if it is the last line of
+ * the paragraph (last word is a forced
+ * break); otherwise, it is the value of the
+ * last paragraph. For this reason, consider
+ * also parMax. */
+ int parMax; /* The maximal total width down from the last
+ * paragraph start, to the *end* of this line.
+ * The space at the end of this line is
+ * included, but not the hyphen width (as
+ * opposed to the other values). So, in some
+ * cases, the space has to be subtracted and
+ * the hyphen width to be added, to compare it
+ * to maxParMax. (Search the code for
+ * occurances.) */
};
struct Word
@@ -228,15 +338,39 @@ protected:
core::Requisition size;
/* Space after the word, only if it's not a break: */
short origSpace; /* from font, set by addSpace */
+ short stretchability, shrinkability;
short effSpace; /* effective space, set by wordWrap,
* used for drawing etc. */
+ short hyphenWidth; /* Additional width, when a word is part
+ * (except the last part) of a hyphenationed
+ * word. Has to be added to the width, when
+ * this is the last word of the line, and
+ * "hyphenWidth > 0" is also used to decide
+ * weather to draw a hyphen. */
core::Content content;
+ bool canBeHyphenated;
+
+ // accumulated values, relative to the beginning of the line
+ int totalWidth; /* The sum of all word widths; plus all
+ spaces, excluding the one of this
+ word; plus the hypthen width of this
+ word (but of course, no hyphen
+ widths of previous words. In other
+ words: the value compared to the
+ ideal width of the line, if the line
+ would be broken after this word. */
+ int totalStretchability; // includes all *before* current word
+ int totalShrinkability; // includes all *before* current word
+ BadnessAndPenalty badnessAndPenalty; /* when line is broken after this
+ * word */
core::style::Style *style;
core::style::Style *spaceStyle; /* initially the same as of the word,
later set by a_Dw_page_add_space */
};
+ void printWord (Word *word);
+
struct Anchor
{
char *name;
@@ -303,13 +437,11 @@ protected:
/* These values are set by set_... */
int availWidth, availAscent, availDescent;
- int lastLineWidth;
- int lastLineParMin;
- int lastLineParMax;
int wrapRef; /* [0 based] */
lout::misc::SimpleVector <Line> *lines;
- lout::misc::SimpleVector <Word> *words;
+ int nonTemporaryLines;
+ lout::misc::NotSoSimpleVector <Word> *words;
lout::misc::SimpleVector <Anchor> *anchors;
struct {int index, nChar;}
@@ -321,23 +453,38 @@ protected:
void queueDrawRange (int index1, int index2);
void getWordExtremes (Word *word, core::Extremes *extremes);
void markChange (int ref);
- void justifyLine (Line *line, int availWidth);
- Line *addLine (int wordInd, bool newPar);
+ void justifyLine (Line *line, int diff);
+ Line *addLine (int firstWord, int lastWord, bool temporary);
void calcWidgetSize (core::Widget *widget, core::Requisition *size);
void rewrap ();
- void decorateText(core::View *view, core::style::Style *style,
- core::style::Color::Shading shading,
- int x, int yBase, int width);
- void drawText(int wordIndex, core::View *view, core::Rectangle *area,
- int xWidget, int yWidgetBase);
- void drawSpace(int wordIndex, core::View *view, core::Rectangle *area,
- int xWidget, int yWidgetBase);
+ void showMissingLines ();
+ void removeTemporaryLines ();
+
+ void decorateText (core::View *view, core::style::Style *style,
+ core::style::Color::Shading shading,
+ int x, int yBase, int width);
+ 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);
+ void drawWord (Line *line, int wordIndex1, int wordIndex2, core::View *view,
+ core::Rectangle *area, int xWidget, int yWidgetBase);
+ void drawWord0 (int wordIndex1, int wordIndex2,
+ const char *text, int totalWidth,
+ core::style::Style *style, core::View *view,
+ core::Rectangle *area, int xWidget, int yWidgetBase);
+ void drawSpace (int wordIndex, core::View *view, core::Rectangle *area,
+ int xWidget, int yWidgetBase);
void drawLine (Line *line, core::View *view, core::Rectangle *area);
int findLineIndex (int y);
int findLineOfWord (int wordIndex);
Word *findWord (int x, int y, bool *inSpace);
- Word *addWord (int width, int ascent, int descent,
+ Word *addWord (int width, int ascent, int descent, bool canBeHyphenated,
+ core::style::Style *style);
+ void fillWord (Word *word, int width, int ascent, int descent,
+ bool canBeHyphenated, core::style::Style *style);
+ void fillSpace (Word *word, core::style::Style *style);
+ int textWidth (const char *text, int start, int len,
core::style::Style *style);
void calcTextSize (const char *text, size_t len, core::style::Style *style,
core::Requisition *size);
@@ -361,7 +508,7 @@ protected:
inline int lineXOffsetContents (Line *line)
{
return innerPadding + line->leftOffset + line->boxLeft +
- (line == lines->getRef (0) ? line1OffsetEff : 0);
+ (line == lines->getFirstRef() ? line1OffsetEff : 0);
}
/**
@@ -414,7 +561,15 @@ protected:
bool sendSelectionEvent (core::SelectionState::EventType eventType,
core::MousePositionEvent *event);
- virtual void wordWrap(int wordIndex);
+ void accumulateWordExtremes (int firstWord, int lastWord,
+ int *maxOfMinWidth, int *sumOfMaxWidth);
+ virtual void wordWrap (int wordIndex, bool wrapAll);
+ int hyphenateWord (int wordIndex);
+ void accumulateWordForLine (int lineIndex, int wordIndex);
+ void accumulateWordData(int wordIndex);
+ int calcAvailWidth (int lineIndex);
+ void initLine1Offset (int wordIndex);
+ void alignLine (int lineIndex);
void sizeRequestImpl (core::Requisition *requisition);
void getExtremesImpl (core::Extremes *extremes);
@@ -438,6 +593,13 @@ protected:
void removeChild (Widget *child);
+ void addText0 (const char *text, size_t len, bool canBeHyphenated,
+ core::style::Style *style, core::Requisition *size);
+ void calcTextSizes (const char *text, size_t textLen,
+ core::style::Style *style,
+ int numBreaks, int *breakPos,
+ core::Requisition *wordSize);
+
public:
static int CLASS_ID;
@@ -455,7 +617,25 @@ public:
}
void addWidget (core::Widget *widget, core::style::Style *style);
bool addAnchor (const char *name, core::style::Style *style);
- void addSpace(core::style::Style *style);
+ void addSpace (core::style::Style *style);
+
+ inline void addBreakOption (core::style::Style *style)
+ {
+ int wordIndex = words->size () - 1;
+ if (wordIndex >= 0)
+ addBreakOption (words->getRef(wordIndex), style);
+ }
+
+ // TODO Re-evaluate again. When needed, which penalty values, etc.
+ inline void addBreakOption (Word *word, core::style::Style *style)
+ {
+ if (style->whiteSpace != core::style::WHITE_SPACE_NOWRAP &&
+ style->whiteSpace != core::style::WHITE_SPACE_PRE)
+ if (word->badnessAndPenalty.lineMustBeBroken())
+ word->badnessAndPenalty.setPenalty (0);
+ }
+
+ void addHyphen();
void addParbreak (int space, core::style::Style *style);
void addLinebreak (core::style::Style *style);