mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-12 18:40:29 +00:00
(svn r25482) -Fix [FS#5620]: forced newlines were not properly handled
This commit is contained in:
parent
bd2f4b9a24
commit
569eaf0e11
@ -105,25 +105,25 @@ size_t Layouter::AppendToBuffer(UChar *buff, const UChar *buffer_last, WChar c)
|
|||||||
return length;
|
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) {
|
if (length == 0) {
|
||||||
/* ICU's ParagraphLayout cannot handle empty strings, so fake one. */
|
/* ICU's ParagraphLayout cannot handle empty strings, so fake one. */
|
||||||
this->buffer[0] = ' ';
|
buff[0] = ' ';
|
||||||
length = 1;
|
length = 1;
|
||||||
this->fonts.End()[-1].first++;
|
fontMapping.End()[-1].first++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill ICU's FontRuns with the right data. */
|
/* Fill ICU's FontRuns with the right data. */
|
||||||
FontRuns runs(this->fonts.Length());
|
FontRuns runs(fontMapping.Length());
|
||||||
for (FontMap::iterator iter = this->fonts.Begin(); iter != this->fonts.End(); iter++) {
|
for (FontMap::iterator iter = fontMapping.Begin(); iter != fontMapping.End(); iter++) {
|
||||||
runs.add(iter->second, iter->first);
|
runs.add(iter->second, iter->first);
|
||||||
}
|
}
|
||||||
|
|
||||||
LEErrorCode status = LE_NO_ERROR;
|
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 */
|
#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 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.
|
* - 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();
|
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;
|
const WChar *begin = this->buffer;
|
||||||
WChar *last_space = NULL;
|
WChar *last_space = NULL;
|
||||||
const WChar *last_char = begin;
|
const WChar *last_char = begin;
|
||||||
int width = 0;
|
int width = 0;
|
||||||
|
|
||||||
int offset = this->buffer - this->buffer_begin;
|
int offset = this->buffer - this->buffer_begin;
|
||||||
FontMap::iterator iter = runs.Begin();
|
FontMap::iterator iter = this->runs.Begin();
|
||||||
while (iter->first <= offset) {
|
while (iter->first <= offset) {
|
||||||
iter++;
|
iter++;
|
||||||
assert(iter != runs.End());
|
assert(iter != this->runs.End());
|
||||||
}
|
}
|
||||||
|
|
||||||
const FontCache *fc = iter->second->fc;
|
const FontCache *fc = iter->second->fc;
|
||||||
@ -303,12 +310,11 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
|
|||||||
this->buffer = NULL;
|
this->buffer = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c == '\n') break;
|
|
||||||
|
|
||||||
if (this->buffer == next_run) {
|
if (this->buffer == next_run) {
|
||||||
*l->Append() = new VisualRun(iter->second, begin, this->buffer - begin, l->getWidth());
|
*l->Append() = new VisualRun(iter->second, begin, this->buffer - begin, l->getWidth());
|
||||||
iter++;
|
iter++;
|
||||||
assert(iter != runs.End());
|
assert(iter != this->runs.End());
|
||||||
|
|
||||||
next_run = this->buffer_begin + iter->first + 1;
|
next_run = this->buffer_begin + iter->first + 1;
|
||||||
begin = this->buffer;
|
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());
|
*l->Append() = new VisualRun(iter->second, begin, last_char - begin, l->getWidth());
|
||||||
}
|
}
|
||||||
return l;
|
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.
|
* 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 buff_end The location after the last element in the buffer.
|
||||||
|
* @param fontMapping THe mapping of the fonts.
|
||||||
* @return The ParagraphLayout instance.
|
* @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 */
|
#endif /* !WITH_ICU */
|
||||||
|
|
||||||
@ -393,61 +401,70 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi
|
|||||||
CharType *buff = this->buffer;
|
CharType *buff = this->buffer;
|
||||||
|
|
||||||
TextColour cur_colour = colour, prev_colour = colour;
|
TextColour cur_colour = colour, prev_colour = colour;
|
||||||
Font *f = new Font(fontsize, cur_colour);
|
WChar c;
|
||||||
|
|
||||||
/*
|
do {
|
||||||
* Go through the whole string while adding Font instances to the font map
|
Font *f = new Font(fontsize, cur_colour);
|
||||||
* whenever the font changes, and convert the wide characters into a format
|
CharType *buff_begin = buff;
|
||||||
* usable by ParagraphLayout.
|
FontMap fontMapping;
|
||||||
*/
|
|
||||||
for (; buff < buffer_last;) {
|
/*
|
||||||
WChar c = Utf8Consume(const_cast<const char **>(&str));
|
* Go through the whole string while adding Font instances to the font map
|
||||||
if (c == 0) {
|
* whenever the font changes, and convert the wide characters into a format
|
||||||
break;
|
* usable by ParagraphLayout.
|
||||||
} else if (c >= SCC_BLUE && c <= SCC_BLACK) {
|
*/
|
||||||
prev_colour = cur_colour;
|
for (; buff < buffer_last;) {
|
||||||
cur_colour = (TextColour)(c - SCC_BLUE);
|
c = Utf8Consume(const_cast<const char **>(&str));
|
||||||
} else if (c == SCC_PREVIOUS_COLOUR) { // Revert to the previous colour.
|
if (c == '\0' || c == '\n') {
|
||||||
Swap(prev_colour, cur_colour);
|
break;
|
||||||
} else if (c == SCC_TINYFONT) {
|
} else if (c >= SCC_BLUE && c <= SCC_BLACK) {
|
||||||
fontsize = FS_SMALL;
|
prev_colour = cur_colour;
|
||||||
} else if (c == SCC_BIGFONT) {
|
cur_colour = (TextColour)(c - SCC_BLUE);
|
||||||
fontsize = FS_LARGE;
|
} else if (c == SCC_PREVIOUS_COLOUR) { // Revert to the previous colour.
|
||||||
} else {
|
Swap(prev_colour, cur_colour);
|
||||||
buff += AppendToBuffer(buff, buffer_last, c);
|
} else if (c == SCC_TINYFONT) {
|
||||||
continue;
|
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)) {
|
/* Better safe than sorry. */
|
||||||
this->fonts.Insert(buff - this->buffer, f);
|
*buff = '\0';
|
||||||
} else {
|
|
||||||
delete f;
|
if (!fontMapping.Contains(buff - buff_begin)) {
|
||||||
|
fontMapping.Insert(buff - buff_begin, f);
|
||||||
|
*this->fonts.Append() = f;
|
||||||
}
|
}
|
||||||
f = new Font(fontsize, cur_colour);
|
ParagraphLayout *p = GetParagraphLayout(buff_begin, buff, fontMapping);
|
||||||
}
|
|
||||||
|
|
||||||
/* Better safe than sorry. */
|
/* Copy all lines into a local cache so we can reuse them later on more easily. */
|
||||||
*buff = '\0';
|
ParagraphLayout::Line *l;
|
||||||
|
while ((l = p->nextLine(maxw)) != NULL) {
|
||||||
|
*this->Append() = l;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this->fonts.Contains(buff - this->buffer)) {
|
delete p;
|
||||||
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. */
|
} while (c != '\0' && buff < buffer_last);
|
||||||
ParagraphLayout::Line *l;
|
|
||||||
while ((l = p->nextLine(maxw)) != NULL) {
|
|
||||||
*this->Append() = l;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Free everything we allocated. */
|
/** Free everything we allocated. */
|
||||||
Layouter::~Layouter()
|
Layouter::~Layouter()
|
||||||
{
|
{
|
||||||
for (FontMap::iterator iter = this->fonts.Begin(); iter != this->fonts.End(); iter++) {
|
for (Font **iter = this->fonts.Begin(); iter != this->fonts.End(); iter++) {
|
||||||
delete iter->second;
|
delete *iter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
#include "gfx_func.h"
|
#include "gfx_func.h"
|
||||||
#include "core/smallmap_type.hpp"
|
#include "core/smallmap_type.hpp"
|
||||||
|
|
||||||
|
#undef WITH_ICU
|
||||||
|
|
||||||
#ifdef WITH_ICU
|
#ifdef WITH_ICU
|
||||||
#include "layout/ParagraphLayout.h"
|
#include "layout/ParagraphLayout.h"
|
||||||
#define ICU_FONTINSTANCE : public LEFontInstance
|
#define ICU_FONTINSTANCE : public LEFontInstance
|
||||||
@ -125,10 +127,10 @@ class Layouter : public AutoDeleteSmallVector<ParagraphLayout::Line *, 4> {
|
|||||||
#endif /* WITH_ICU */
|
#endif /* WITH_ICU */
|
||||||
|
|
||||||
size_t AppendToBuffer(CharType *buff, const CharType *buffer_last, WChar c);
|
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.
|
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:
|
public:
|
||||||
Layouter(const char *str, int maxw = INT32_MAX, TextColour colour = TC_FROMSTRING, FontSize fontsize = FS_NORMAL);
|
Layouter(const char *str, int maxw = INT32_MAX, TextColour colour = TC_FROMSTRING, FontSize fontsize = FS_NORMAL);
|
||||||
|
Loading…
Reference in New Issue
Block a user