Dillo
textblock.hh
Go to the documentation of this file.
1 #ifndef __DW_TEXTBLOCK_HH__
2 #define __DW_TEXTBLOCK_HH__
3 
4 #include <limits.h>
5 
6 #include "core.hh"
7 #include "../lout/misc.hh"
8 
9 // These were used when improved line breaking and hyphenation were
10 // implemented. Should be cleaned up; perhaps reactivate RTFL again.
11 #define PRINTF(fmt, ...)
12 #define PUTCHAR(ch)
13 
14 namespace dw {
15 
144 class Textblock: public core::Widget
145 {
146 private:
156  {
157  private:
159  badnessState;
161  int ratio; // ratio is only defined when badness is defined
163 
164  // for debugging:
166 
167  // "Infinity levels" are used to represent very large numbers,
168  // including "quasi-infinite" numbers. A couple of infinity
169  // level and number can be mathematically represented as
170  //
171  // number * N ^ (infinity level)
172  //
173  // where N is a number which is large enough. Practically,
174  // infinity levels are used to circumvent limited ranges for
175  // integer numbers.
176 
177  // Here, all infinity levels have got special meanings.
178  enum {
179  INF_VALUE = 0, /* simple values */
180  INF_LARGE, /* large values, like QUITE_LOOSE */
181  INF_NOT_STRETCHABLE, /* reserved for NOT_STRECTHABLE */
182  INF_TOO_TIGHT, /* used for lines, which are too tight */
183  INF_PENALTIES, /* used for penalties */
185 
186  // That INF_PENALTIES is the last value means that an
187  // infinite penalty (breaking is prohibited) makes a break
188  // not possible at all, so that pre-formatted text
189  // etc. works.
190  };
191 
192  int badnessValue (int infLevel);
193  int penaltyValue (int infLevel);
194 
195  public:
196  void calcBadness (int totalWidth, int idealWidth,
198  void setPenalty (int penalty);
199  void setPenaltyProhibitBreak ();
200  void setPenaltyForceBreak ();
201 
202  bool lineLoose ();
203  bool lineTight ();
204  bool lineTooTight ();
205  bool lineMustBeBroken ();
206  bool lineCanBeBroken ();
207  int compareTo (BadnessAndPenalty *other);
208 
209  void print ();
210  };
211 
212 protected:
213  enum {
220  };
221 
222  struct Line
223  {
224  int firstWord; /* first word's index in word vector */
225  int lastWord; /* last word's index in word vector */
226 
227  /* "top" is always relative to the top of the first line, i.e.
228  * page->lines[0].top is always 0. */
231 
232  /* This is similar to descent, but includes the bottom margins of the
233  * widgets within this line. */
235 
236  /* The following members contain accumulated values, from the
237  * top down to this line. Please notice a change: until
238  * recently, the values were accumulated up to the last line,
239  * not this line.
240  *
241  * Also, keep in mind that at the end of a line, the space of
242  * the last word is ignored, but instead, the hyphen width must
243  * be considered.*/
244 
245  int maxLineWidth; /* Maximum of all line widths, including this
246  * line. Does not include the last space, but
247  * the last hyphen width. */
248  int maxParMin; /* Maximum of all paragraph minima, including
249  * this line. */
250  int maxParMax; /* Maximum of all paragraph maxima. This line
251  * is only included, if it is the last line of
252  * the paragraph (last word is a forced
253  * break); otherwise, it is the value of the
254  * last paragraph. For this reason, consider
255  * also parMax. */
256  int parMax; /* The maximal total width down from the last
257  * paragraph start, to the *end* of this line.
258  * The space at the end of this line is
259  * included, but not the hyphen width (as
260  * opposed to the other values). So, in some
261  * cases, the space has to be subtracted and
262  * the hyphen width to be added, to compare it
263  * to maxParMax. (Search the code for
264  * occurances.) */
265  };
266 
267  struct Word
268  {
269  /* TODO: perhaps add a xLeft? */
271  /* Space after the word, only if it's not a break: */
272  short origSpace; /* from font, set by addSpace */
274  short effSpace; /* effective space, set by wordWrap,
275  * used for drawing etc. */
276  short hyphenWidth; /* Additional width, when a word is part
277  * (except the last part) of a hyphenationed
278  * word. Has to be added to the width, when
279  * this is the last word of the line, and
280  * "hyphenWidth > 0" is also used to decide
281  * whether to draw a hyphen. */
284 
285  // accumulated values, relative to the beginning of the line
286  int totalWidth; /* The sum of all word widths; plus all
287  spaces, excluding the one of this
288  word; plus the hyphen width of this
289  word (but of course, no hyphen
290  widths of previous words. In other
291  words: the value compared to the
292  ideal width of the line, if the line
293  would be broken after this word. */
294  int totalStretchability; // includes all *before* current word
295  int totalShrinkability; // includes all *before* current word
296  BadnessAndPenalty badnessAndPenalty; /* when line is broken after this
297  * word */
298 
300  core::style::Style *spaceStyle; /* initially the same as of the word,
301  later set by a_Dw_page_add_space */
302  };
303 
304  void printWord (Word *word);
305 
306  struct Anchor
307  {
308  char *name;
310  };
311 
313  {
314  private:
315  int index;
316 
317  public:
319  bool atEnd);
321  int index);
322 
324  int compareTo(lout::misc::Comparable *other);
325 
326  bool next ();
327  bool prev ();
328  void highlight (int start, int end, core::HighlightLayer layer);
329  void unhighlight (int direction, core::HighlightLayer layer);
330  void getAllocation (int start, int end, core::Allocation *allocation);
331  };
332 
333  friend class TextblockIterator;
334 
335  /* These fields provide some ad-hoc-functionality, used by sub-classes. */
336  bool hasListitemValue; /* If true, the first word of the page is treated
337  specially (search in source). */
338  int innerPadding; /* This is an additional padding on the left side
339  (used by ListItem). */
340  int line1Offset; /* This is an additional offset of the first line.
341  May be negative (shift to left) or positive
342  (shift to right). */
343  int line1OffsetEff; /* The "effective" value of line1_offset, may
344  differ from line1_offset when
345  ignoreLine1OffsetSometimes is set to true. */
346 
347  /* The following is really hackish: It is used for DwTableCell (see
348  * comment in dw_table_cell.c), to avoid too wide table columns. If
349  * set to true, it has following effects:
350  *
351  * (i) line1_offset is ignored in calculating the minimal width
352  * (which is used by DwTable!), and
353  * (ii) line1_offset is ignored (line1_offset_eff is set to 0),
354  * when line1_offset plus the width of the first word is
355  * greater than the the available witdh.
356  *
357  * \todo Eliminate all these ad-hoc features by a new, simpler and
358  * more elegant design. ;-)
359  */
361 
363 
364  bool limitTextWidth; /* from preferences */
365 
366  int redrawY;
368 
369  /* These values are set by set_... */
371 
372  int wrapRef; /* [0 based] */
373 
378 
379  struct {int index, nChar;}
381 
382  int hoverLink; /* The link under the mouse pointer */
383 
384 
385  void queueDrawRange (int index1, int index2);
387  void markChange (int ref);
388  void justifyLine (Line *line, int diff);
389  Line *addLine (int firstWord, int lastWord, bool temporary);
390  void calcWidgetSize (core::Widget *widget, core::Requisition *size);
391  void rewrap ();
392  void showMissingLines ();
393  void removeTemporaryLines ();
394 
397  int x, int yBase, int width);
399  core::style::Color::Shading shading, int x, int y,
400  const char *text, int start, int len);
401  void drawWord (Line *line, int wordIndex1, int wordIndex2, core::View *view,
402  core::Rectangle *area, int xWidget, int yWidgetBase);
403  void drawWord0 (int wordIndex1, int wordIndex2,
404  const char *text, int totalWidth,
406  core::Rectangle *area, int xWidget, int yWidgetBase);
407  void drawSpace (int wordIndex, core::View *view, core::Rectangle *area,
408  int xWidget, int yWidgetBase);
409  void drawLine (Line *line, core::View *view, core::Rectangle *area);
410  int findLineIndex (int y);
411  int findLineOfWord (int wordIndex);
412  Word *findWord (int x, int y, bool *inSpace);
413 
414  Word *addWord (int width, int ascent, int descent, bool canBeHyphenated,
416  void fillWord (Word *word, int width, int ascent, int descent,
417  bool canBeHyphenated, core::style::Style *style);
418  void fillSpace (Word *word, core::style::Style *style);
420  int textWidth (const char *text, int start, int len,
422  void calcTextSize (const char *text, size_t len, core::style::Style *style,
423  core::Requisition *size);
424 
432  inline int lineXOffsetContents (Line *line)
433  {
434  return innerPadding + line->leftOffset +
435  (line == lines->getFirstRef() ? line1OffsetEff : 0);
436  }
437 
442  inline int lineXOffsetWidget (Line *line)
443  {
444  return lineXOffsetContents (line) + getStyle()->boxOffsetX ();
445  }
446 
449  {
450  return line->top + (allocation->ascent - lines->getRef(0)->boxAscent);
451  }
452 
453  inline int lineYOffsetWidget (Line *line)
454  {
455  return lineYOffsetWidgetAllocation (line, &allocation);
456  }
457 
463  {
464  return allocation->y + lineYOffsetWidgetAllocation(line, allocation);
465  }
466 
470  inline int lineYOffsetCanvas (Line *line)
471  {
473  }
474 
475  inline int lineYOffsetWidgetI (int lineIndex)
476  {
477  return lineYOffsetWidget (lines->getRef (lineIndex));
478  }
479 
480  inline int lineYOffsetCanvasI (int lineIndex)
481  {
482  return lineYOffsetCanvas (lines->getRef (lineIndex));
483  }
484 
486  core::MousePositionEvent *event);
487 
488  void accumulateWordExtremes (int firstWord, int lastWord,
489  int *maxOfMinWidth, int *sumOfMaxWidth);
490  virtual void wordWrap (int wordIndex, bool wrapAll);
491  int hyphenateWord (int wordIndex);
492  void accumulateWordForLine (int lineIndex, int wordIndex);
493  void accumulateWordData(int wordIndex);
494  int calcAvailWidth (int lineIndex);
495  void initLine1Offset (int wordIndex);
496  void alignLine (int lineIndex);
497 
501  void resizeDrawImpl ();
502 
503  void markSizeChange (int ref);
504  void markExtremesChange (int ref);
505  void setWidth (int width);
506  void setAscent (int ascent);
507  void setDescent (int descent);
508  void draw (core::View *view, core::Rectangle *area);
509 
510  bool buttonPressImpl (core::EventButton *event);
511  bool buttonReleaseImpl (core::EventButton *event);
512  bool motionNotifyImpl (core::EventMotion *event);
513  void enterNotifyImpl (core::EventCrossing *event);
514  void leaveNotifyImpl (core::EventCrossing *event);
515 
516  void removeChild (Widget *child);
517 
518  void addText0 (const char *text, size_t len, bool canBeHyphenated,
520  void calcTextSizes (const char *text, size_t textLen,
522  int numBreaks, int *breakPos,
523  core::Requisition *wordSize);
524 
525 public:
526  static int CLASS_ID;
527 
529  ~Textblock();
530 
531  core::Iterator *iterator (core::Content::Type mask, bool atEnd);
532 
533  void flush ();
534 
535  void addText (const char *text, size_t len, core::style::Style *style);
536  inline void addText (const char *text, core::style::Style *style)
537  {
538  addText (text, strlen(text), style);
539  }
541  bool addAnchor (const char *name, core::style::Style *style);
543 
549  {
550  int wordIndex = words->size () - 1;
551  if (wordIndex >= 0)
552  setBreakOption (words->getRef(wordIndex), style);
553  }
554 
555  void addHyphen();
556  void addParbreak (int space, core::style::Style *style);
558 
559  core::Widget *getWidgetAtPoint (int x, int y, int level);
561  void changeLinkColor (int link, int newColor);
562  void changeWordStyle (int from, int to, core::style::Style *style,
563  bool includeFirstSpace, bool includeLastSpace);
564 };
565 
566 } // namespace dw
567 
568 #endif // __DW_TEXTBLOCK_HH__