white-space patch

Johannes Hofmann <[email protected]>
Newsgroups gmane.comp.web.dillo.devel
Message-ID <[email protected]>
Hi,

attached is a preliminary patch for white-space: nowrap handling.
It' supposed to fix the following issues:

* Weird page width in combination with white-space:nowrap sequences
  (e.g. on http://en.wikipedia.org/wiki/Web_browser.
* Line breaks at tags (e.g. <b>D</b>illo should not break after
  the "D".  (similar issue on
  http://fltk.org/newsgroups.php?gfltk.development+T) 

without breaking:

* zero width space handling.
* ideographic character handling.

It's not ready for commit yet, as google results don't render
deterministically the same way.
Nevertheless please give it a try and report how it works for you.

Cheers,
Johannes

_______________________________________________
Dillo-dev mailing list
[email protected]
http://lists.auriga.wearlab.de/cgi-bin/mailman/listinfo/dillo-dev
whitespace-fixes2.diff (text/plain, 9.6 KB)
diff --git a/dw/textblock.cc b/dw/textblock.cc
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -202,10 +202,9 @@
 {
    core::Extremes wordExtremes;
    Line *line;
-   Word *word;
+   Word *word, *prevWord = NULL;
    int wordIndex, lineIndex;
    int parMin, parMax;
-   bool nowrap;
 
    //DBG_MSG (widget, "extremes", 0, "Dw_page_get_extremes");
    //DBG_MSG_START (widget);
@@ -250,15 +249,9 @@
       for (lineIndex = wrapRef; lineIndex < lines->size (); lineIndex++) {
          //DBG_MSGF (widget, "extremes", 0, "line %d", lineIndex);
          //DBG_MSG_START (widget);
-         core::style::WhiteSpace ws;
+         int nowrapMin = 0;
 
          line = lines->getRef (lineIndex);
-         ws = words->getRef(line->firstWord)->style->whiteSpace;
-         nowrap = ws == core::style::WHITE_SPACE_PRE ||
-                  ws == core::style::WHITE_SPACE_NOWRAP;
-
-         //DEBUG_MSG (DEBUG_SIZE_LEVEL, "   line %d (of %d), nowrap = %d\n",
-         //           lineIndex, page->num_lines, nowrap);
 
          for (wordIndex = line->firstWord; wordIndex <= line->lastWord;
               wordIndex++) {
@@ -272,20 +265,28 @@
                //           "      (next plus %d)\n", page->line1_offset);
             }
 
-            if (nowrap) {
-               parMin += prevWordSpace + wordExtremes.minWidth;
-               //DBG_MSGF (widget, "extremes", 0, "parMin = %d", parMin);
-            } else {
-               if (extremes->minWidth < wordExtremes.minWidth)
-                  extremes->minWidth = wordExtremes.minWidth;
-            }
+
+            if (extremes->minWidth < wordExtremes.minWidth)
+               extremes->minWidth = wordExtremes.minWidth;
 
             _MSG("parMax = %d, wordMaxWidth=%d, prevWordSpace=%d\n",
                  parMax, wordExtremes.maxWidth, prevWordSpace);
             if (word->content.type != core::Content::BREAK)
                parMax += prevWordSpace;
             parMax += wordExtremes.maxWidth;
+
+            if (prevWord && !canBreakAfter(prevWord)) {
+               nowrapMin += prevWordSpace + wordExtremes.minWidth;
+            } else {
+               nowrapMin = wordExtremes.minWidth;
+            }
+
+            if (extremes->minWidth < nowrapMin) {
+               extremes->minWidth = nowrapMin;
+            }
+
             prevWordSpace = word->origSpace;
+            prevWord = word;
 
             //DEBUG_MSG (DEBUG_SIZE_LEVEL + 1,
             //           "      word %s: maxWidth = %d\n",
@@ -305,17 +306,6 @@
             if (extremes->maxWidth < parMax)
                extremes->maxWidth = parMax;
 
-            if (nowrap) {
-               //DBG_MSGF (widget, "extremes", 0, "parMin = %d", parMin);
-               if (extremes->minWidth < parMin)
-                  extremes->minWidth = parMin;
-
-               //DEBUG_MSG (DEBUG_SIZE_LEVEL + 2,
-               //           "   parMin = %d, after word %d (%s)\n",
-               //           parMin, line->last_word - 1,
-               //           a_Dw_content_text (&word->content));
-            }
-
             prevWordSpace = 0;
             parMin = 0;
             parMax = 0;
@@ -887,7 +877,7 @@
    Line *lastLine;
    Word *word;
    int availWidth, lastSpace, leftOffset, len;
-   bool newLine = false, newPar = false;
+   bool newLine = false, newPar = false, canBreakBefore = true;
    core::Extremes wordExtremes;
 
    //DBG_MSGF (page, "wrap", 0, "Dw_page_real_word_wrap (%d): %s, width = %d",
@@ -942,23 +932,32 @@
          /* previous word is a break */
          newLine = true;
          newPar = true;
-      } else if (word->style->whiteSpace == core::style::WHITE_SPACE_NOWRAP ||
-                 word->style->whiteSpace == core::style::WHITE_SPACE_PRE) {
-         //DBG_MSGF (page, "wrap", 0, "no wrap (white_space = %d)",
-         //          word->style->white_space);
+      } else if (!canBreakAfter (prevWord)) {
+         canBreakBefore = false;
+         // no break within nowrap
          newLine = false;
          newPar = false;
+         if (lastLineWidth + prevWord->origSpace + word->size.width >
+             availWidth)
+            markChange (lines->size () - 1);
       } else if (lastLine->firstWord != wordIndex) {
-         /* Does new word fit into the last line? */
-         //DBG_MSGF (page, "wrap", 0,
-         //          "word %d (%s) fits? (%d + %d + %d &lt;= %d)...",
-         //          word_ind, a_Dw_content_html (&word->content),
-         //          page->lastLine_width, prevWord->orig_space,
-         //          word->size.width, availWidth);
-         newLine = lastLineWidth + prevWord->origSpace + word->size.width >
-                   availWidth;
-         //DBG_MSGF (page, "wrap", 0, "... %s.",
-         //          newLine ? "No" : "Yes");
+         // check if we need to break because nowrap sequence is following
+         newLine = false;
+         int lineWidthNeeded = lastLineWidth + prevWord->origSpace;
+         for (int i = wordIndex; i < words->size (); i++) {
+            Word *w = words->getRef (i);
+                       
+            lineWidthNeeded += w->size.width;
+                       
+            if (lineWidthNeeded > availWidth) {
+               newLine = true;
+               break;  
+            } else if (canBreakAfter (w)) {
+               break;
+            }
+
+            lineWidthNeeded += w->origSpace;
+         }
       }
    }
 
@@ -1039,15 +1038,12 @@
    lastLineParMin += wordExtremes.maxWidth;    /* Why maxWidth? */
    lastLineParMax += wordExtremes.maxWidth;
 
-   if (word->style->whiteSpace == core::style::WHITE_SPACE_NOWRAP ||
-       word->style->whiteSpace == core::style::WHITE_SPACE_PRE) {
-      lastLine->parMin += wordExtremes.minWidth + lastSpace;
+   if (!canBreakBefore) {
+      lastNowrapLen += wordExtremes.minWidth + lastSpace;
       /* This may also increase the accumulated minimum word width.  */
-      lastLine->maxWordMin =
-         misc::max (lastLine->maxWordMin, lastLine->parMin);
-      /* NOTE: Most code relies on that all values of nowrap are equal for all
-       * words within one line. */
+      lastLine->maxWordMin = misc::max (lastLine->maxWordMin, lastNowrapLen);
    } else {
+      lastNowrapLen = wordExtremes.minWidth;
       lastLine->maxWordMin =
          misc::max (lastLine->maxWordMin, wordExtremes.minWidth);
    }
@@ -1185,6 +1181,7 @@
     * the line list up from this position is rebuild. */
    lines->setSize (wrapRef);
    lastLineWidth = 0;
+   lastNowrapLen = 0;
    //DBG_OBJ_SET_NUM(page, "num_lines", page->num_lines);
    //DBG_OBJ_SET_NUM(page, "lastLine_width", page->lastLine_width);
 
@@ -1581,6 +1578,7 @@
    word->origSpace = 0;
    word->effSpace = 0;
    word->content.space = false;
+   word->content.breakType = core::Content::BREAK_NO;
 
    //DBG_OBJ_ARRSET_NUM (page, "words.%d.size.width", page->num_words - 1,
    //                    word->size.width);
@@ -1764,6 +1762,8 @@
    if (wordIndex >= 0) {
       Word *word = words->getRef(wordIndex);
 
+      addBreakOption (style);
+ 
       if (!word->content.space) {
          word->content.space = true;
          word->effSpace = word->origSpace = style->font->spaceWidth +
@@ -1782,7 +1782,6 @@
    }
 }
 
-
 /**
  * Cause a paragraph break
  */
diff --git a/dw/textblock.hh b/dw/textblock.hh
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -242,6 +242,7 @@
    int lastLineWidth;
    int lastLineParMin;
    int lastLineParMax;
+   int lastNowrapLen;
    int wrapRef;  /* [0 based] */
 
    lout::misc::SimpleVector <Line> *lines;
@@ -256,6 +257,10 @@
 
    void queueDrawRange (int index1, int index2);
    void getWordExtremes (Word *word, core::Extremes *extremes);
+   inline bool canBreakAfter (Word *word)
+   {
+      return word->content.breakType == core::Content::BREAK_OK;
+   }
    void markChange (int ref);
    void justifyLine (Line *line, int availWidth);
    Line *addLine (int wordInd, bool newPar);
@@ -382,6 +387,14 @@
    void addWidget (core::Widget *widget, core::style::Style *style);
    bool addAnchor (const char *name, 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 &&
+          style->whiteSpace != core::style::WHITE_SPACE_NOWRAP &&
+          style->whiteSpace != core::style::WHITE_SPACE_PRE)
+         words->getRef(wordIndex)->content.breakType = core::Content::BREAK_OK;
+   }
    void addParbreak (int space, core::style::Style *style);
    void addLinebreak (core::style::Style *style);
 
diff --git a/dw/types.hh b/dw/types.hh
--- a/dw/types.hh
+++ b/dw/types.hh
@@ -194,11 +194,16 @@
       REAL_CONTENT      = 0xff ^ (START | END),
       SELECTION_CONTENT = TEXT | WIDGET | BREAK
    };
+   enum BreakType {
+      BREAK_NO,
+      BREAK_OK
+   };
    /* Content is embedded in struct Word therefore we
     * try to be space efficient.
     */
    short type;
    bool space;
+   unsigned char breakType;
    union {
       const char *text;
       Widget *widget;
diff --git a/src/html.cc b/src/html.cc
--- a/src/html.cc
+++ b/src/html.cc
@@ -1208,10 +1208,12 @@
             Html_process_space(html, word2 + start, i - start);
          } else if (!strncmp(word2+i, utf8_zero_width_space, 3)) {
             i += 3;
+            HT2TB(html)->addBreakOption(html->styleEngine->wordStyle ());
          } else if (a_Utf8_ideographic(word2+i, beyond_word2, &len)) {
             i += len;
             HT2TB(html)->addText(word2 + start, i - start,
                                  html->styleEngine->wordStyle ());
+            HT2TB(html)->addBreakOption(html->styleEngine->wordStyle ());
          } else {
             do {
                i += len;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.