summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2013-06-27 16:24:19 +0000
committerrubidium <rubidium@openttd.org>2013-06-27 16:24:19 +0000
commit569eaf0e11bef75146be0064a9c4842916977f21 (patch)
treecc0b63e4a79a6497d78eb0051797c7885dd5e5ba
parentbd2f4b9a244e0547103aad3a9e9ee53a89e27d83 (diff)
downloadopenttd-569eaf0e11bef75146be0064a9c4842916977f21.tar.xz
(svn r25482) -Fix [FS#5620]: forced newlines were not properly handled
-rw-r--r--src/gfx_layout.cpp133
-rw-r--r--src/gfx_layout.h6
2 files changed, 79 insertions, 60 deletions
diff --git a/src/gfx_layout.cpp b/src/gfx_layout.cpp
index 62fb75bc9..f28a35e8f 100644
--- a/src/gfx_layout.cpp
+++ b/src/gfx_layout.cpp
@@ -105,25 +105,25 @@ size_t Layouter::AppendToBuffer(UChar *buff, const UChar *buffer_last, WChar c)
return length;
}
-ParagraphLayout *Layouter::GetParagraphLayout(UChar *buff)
+ParagraphLayout *Layouter::GetParagraphLayout(UChar *buff, UChar *buff_end, FontMap &fontMapping)
{
- int32 length = buff - this->buffer;
+ int32 length = buff_end - buff;
if (length == 0) {
/* ICU's ParagraphLayout cannot handle empty strings, so fake one. */
- this->buffer[0] = ' ';
+ buff[0] = ' ';
length = 1;
- this->fonts.End()[-1].first++;
+ fontMapping.End()[-1].first++;
}
/* Fill ICU's FontRuns with the right data. */
- FontRuns runs(this->fonts.Length());
- for (FontMap::iterator iter = this->fonts.Begin(); iter != this->fonts.End(); iter++) {
+ FontRuns runs(fontMapping.Length());
+ for (FontMap::iterator iter = fontMapping.Begin(); iter != fontMapping.End(); iter++) {
runs.add(iter->second, iter->first);
}
LEErrorCode status = LE_NO_ERROR;
- return new ParagraphLayout(this->buffer, length, &runs, NULL, NULL, NULL, _current_text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, false, status);
+ return new ParagraphLayout(buff, length, &runs, NULL, NULL, NULL, _current_text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, false, status);
}
#else /* WITH_ICU */
@@ -277,20 +277,27 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
* - split a line at a newline character, or at a space where we can break a line.
* - split for a visual run whenever a new line happens, or the font changes.
*/
- if (this->buffer == NULL|| *this->buffer == '\0') return NULL;
+ if (this->buffer == NULL) return NULL;
Line *l = new Line();
+ if (*this->buffer == '\0') {
+ /* Only a newline. */
+ this->buffer = NULL;
+ *l->Append() = new VisualRun(this->runs.Begin()->second, this->buffer, 0, 0);
+ return l;
+ }
+
const WChar *begin = this->buffer;
WChar *last_space = NULL;
const WChar *last_char = begin;
int width = 0;
int offset = this->buffer - this->buffer_begin;
- FontMap::iterator iter = runs.Begin();
+ FontMap::iterator iter = this->runs.Begin();
while (iter->first <= offset) {
iter++;
- assert(iter != runs.End());
+ assert(iter != this->runs.End());
}
const FontCache *fc = iter->second->fc;
@@ -303,12 +310,11 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
this->buffer = NULL;
break;
}
- if (c == '\n') break;
if (this->buffer == next_run) {
*l->Append() = new VisualRun(iter->second, begin, this->buffer - begin, l->getWidth());
iter++;
- assert(iter != runs.End());
+ assert(iter != this->runs.End());
next_run = this->buffer_begin + iter->first + 1;
begin = this->buffer;
@@ -350,7 +356,7 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
}
}
- if (last_char - begin != 0) {
+ if (l->Length() == 0 || last_char - begin != 0) {
*l->Append() = new VisualRun(iter->second, begin, last_char - begin, l->getWidth());
}
return l;
@@ -371,12 +377,14 @@ size_t Layouter::AppendToBuffer(WChar *buff, const WChar *buffer_last, WChar c)
/**
* Get the actual ParagraphLayout for the given buffer.
+ * @param buff The begin of the buffer.
* @param buff_end The location after the last element in the buffer.
+ * @param fontMapping THe mapping of the fonts.
* @return The ParagraphLayout instance.
*/
-ParagraphLayout *Layouter::GetParagraphLayout(WChar *buff_end)
+ParagraphLayout *Layouter::GetParagraphLayout(WChar *buff, WChar *buff_end, FontMap &fontMapping)
{
- return new ParagraphLayout(this->buffer, buff_end - this->buffer, this->fonts);
+ return new ParagraphLayout(buff, buff_end - buff, fontMapping);
}
#endif /* !WITH_ICU */
@@ -393,61 +401,70 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi
CharType *buff = this->buffer;
TextColour cur_colour = colour, prev_colour = colour;
- Font *f = new Font(fontsize, cur_colour);
+ WChar c;
+
+ do {
+ Font *f = new Font(fontsize, cur_colour);
+ CharType *buff_begin = buff;
+ FontMap fontMapping;
+
+ /*
+ * Go through the whole string while adding Font instances to the font map
+ * whenever the font changes, and convert the wide characters into a format
+ * usable by ParagraphLayout.
+ */
+ for (; buff < buffer_last;) {
+ c = Utf8Consume(const_cast<const char **>(&str));
+ if (c == '\0' || c == '\n') {
+ break;
+ } else if (c >= SCC_BLUE && c <= SCC_BLACK) {
+ prev_colour = cur_colour;
+ cur_colour = (TextColour)(c - SCC_BLUE);
+ } else if (c == SCC_PREVIOUS_COLOUR) { // Revert to the previous colour.
+ Swap(prev_colour, cur_colour);
+ } else if (c == SCC_TINYFONT) {
+ fontsize = FS_SMALL;
+ } else if (c == SCC_BIGFONT) {
+ fontsize = FS_LARGE;
+ } else {
+ buff += AppendToBuffer(buff, buffer_last, c);
+ continue;
+ }
- /*
- * Go through the whole string while adding Font instances to the font map
- * whenever the font changes, and convert the wide characters into a format
- * usable by ParagraphLayout.
- */
- for (; buff < buffer_last;) {
- WChar c = Utf8Consume(const_cast<const char **>(&str));
- if (c == 0) {
- break;
- } else if (c >= SCC_BLUE && c <= SCC_BLACK) {
- prev_colour = cur_colour;
- cur_colour = (TextColour)(c - SCC_BLUE);
- } else if (c == SCC_PREVIOUS_COLOUR) { // Revert to the previous colour.
- Swap(prev_colour, cur_colour);
- } else if (c == SCC_TINYFONT) {
- fontsize = FS_SMALL;
- } else if (c == SCC_BIGFONT) {
- fontsize = FS_LARGE;
- } else {
- buff += AppendToBuffer(buff, buffer_last, c);
- continue;
+ if (!fontMapping.Contains(buff - buff_begin)) {
+ fontMapping.Insert(buff - buff_begin, f);
+ *this->fonts.Append() = f;
+ } else {
+ delete f;
+ }
+ f = new Font(fontsize, cur_colour);
}
- if (!this->fonts.Contains(buff - this->buffer)) {
- this->fonts.Insert(buff - this->buffer, f);
- } else {
- delete f;
- }
- f = new Font(fontsize, cur_colour);
- }
+ /* Better safe than sorry. */
+ *buff = '\0';
- /* Better safe than sorry. */
- *buff = '\0';
+ if (!fontMapping.Contains(buff - buff_begin)) {
+ fontMapping.Insert(buff - buff_begin, f);
+ *this->fonts.Append() = f;
+ }
+ ParagraphLayout *p = GetParagraphLayout(buff_begin, buff, fontMapping);
- if (!this->fonts.Contains(buff - this->buffer)) {
- this->fonts.Insert(buff - this->buffer, f);
- }
- ParagraphLayout *p = GetParagraphLayout(buff);
+ /* Copy all lines into a local cache so we can reuse them later on more easily. */
+ ParagraphLayout::Line *l;
+ while ((l = p->nextLine(maxw)) != NULL) {
+ *this->Append() = l;
+ }
- /* Copy all lines into a local cache so we can reuse them later on more easily. */
- ParagraphLayout::Line *l;
- while ((l = p->nextLine(maxw)) != NULL) {
- *this->Append() = l;
- }
+ delete p;
- delete p;
+ } while (c != '\0' && buff < buffer_last);
}
/** Free everything we allocated. */
Layouter::~Layouter()
{
- for (FontMap::iterator iter = this->fonts.Begin(); iter != this->fonts.End(); iter++) {
- delete iter->second;
+ for (Font **iter = this->fonts.Begin(); iter != this->fonts.End(); iter++) {
+ delete *iter;
}
}
diff --git a/src/gfx_layout.h b/src/gfx_layout.h
index f66559e22..294b70311 100644
--- a/src/gfx_layout.h
+++ b/src/gfx_layout.h
@@ -16,6 +16,8 @@
#include "gfx_func.h"
#include "core/smallmap_type.hpp"
+#undef WITH_ICU
+
#ifdef WITH_ICU
#include "layout/ParagraphLayout.h"
#define ICU_FONTINSTANCE : public LEFontInstance
@@ -125,10 +127,10 @@ class Layouter : public AutoDeleteSmallVector<ParagraphLayout::Line *, 4> {
#endif /* WITH_ICU */
size_t AppendToBuffer(CharType *buff, const CharType *buffer_last, WChar c);
- ParagraphLayout *GetParagraphLayout(CharType *buff);
+ ParagraphLayout *GetParagraphLayout(CharType *buff, CharType *buff_end, FontMap &fontMapping);
CharType buffer[DRAW_STRING_BUFFER]; ///< Buffer for the text that is going to be drawn.
- FontMap fonts; ///< The fonts needed for drawing.
+ SmallVector<Font *, 4> fonts; ///< The fonts needed for drawing.
public:
Layouter(const char *str, int maxw = INT32_MAX, TextColour colour = TC_FROMSTRING, FontSize fontsize = FS_NORMAL);