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 <= %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;