mirror of https://github.com/OpenTTD/OpenTTD
(svn r26021) [1.3] -Backport from trunk:
- Fix: Crash when the ICU layouter thinks a font is corrupted [FS#5711] (r26018, r26017, r26016, r26015) - Fix: Having trains miss a platform that is just being modified is less of a problem than having trains stop twice without moving [FS#5684] (r26013) - Fix: --help text of ./configure for packages that require pkg-config (r26011) - Fix: The AI/GS library name to use in Import, is not the name given by GetName but GetInstanceName [FS#5662] (r26010)release/1.3
parent
5a82846fb0
commit
9fdc7a4ec9
|
@ -3631,12 +3631,13 @@ showhelp() {
|
|||
echo " --with-cocoa enables COCOA video driver (OSX ONLY)"
|
||||
echo " --with-sdl[=sdl-config] enables SDL video driver support"
|
||||
echo " --with-zlib[=zlib.a] enables zlib support"
|
||||
echo " --with-liblzma[=liblzma.a] enables liblzma support"
|
||||
echo " --with-liblzma[=\"pkg-config liblzma\"]"
|
||||
echo " enables liblzma support"
|
||||
echo " --with-liblzo2[=liblzo2.a] enables liblzo2 support"
|
||||
echo " --with-png[=libpng-config] enables libpng support"
|
||||
echo " --with-freetype[=freetype-config]"
|
||||
echo " enables libfreetype support"
|
||||
echo " --with-fontconfig[=pkg-config fontconfig]"
|
||||
echo " --with-fontconfig[=\"pkg-config fontconfig\"]"
|
||||
echo " enables fontconfig support"
|
||||
echo " --with-icu[=icu-config] enables icu (used for right-to-left support)"
|
||||
echo " --static-icu try to link statically (libsicu instead of"
|
||||
|
|
|
@ -403,3 +403,44 @@ Mouse cursor going missing with SDL [FS#4997]:
|
|||
We cannot fix this problem as SDL simply does not provide the
|
||||
required information in these corner cases. This is a bug in SDL
|
||||
and as such there is little that we can do about it.
|
||||
|
||||
Inconsistent catchment areas [FS#5661]:
|
||||
Due to performance decisions the catchment area for cargo accepted
|
||||
by a station for delivery to houses or industries differs from the
|
||||
catchment area for cargo that is delivered to stations from houses
|
||||
or industries.
|
||||
|
||||
Conceptually they work the same, but the effect in game differs.
|
||||
They work by finding the closest destination "around" the source
|
||||
which is within a certain distance. This distance depends on the
|
||||
type of station, e.g. road stops have a smaller catchment area than
|
||||
large airports. In both cases the bounding box, the smallest
|
||||
rectangle that contains all tiles of something, is searched for the
|
||||
target of the cargo, and then spiraling outwards finding the closest
|
||||
tile of the target.
|
||||
|
||||
In the case of a station with two tiles spread far apart with a house
|
||||
that is within the station's bounding box, it would be possible that
|
||||
the spiraling search from the house does not reach one of the station
|
||||
tiles before the search ends, i.e. all tiles within that distance
|
||||
are searched. So the house does not deliver cargo to the station. On
|
||||
the other hand, the station will deliver cargo because the house
|
||||
falls within the bounding box, and thus search area.
|
||||
|
||||
It is possible to make these consistent, but then cargo from a house
|
||||
to a station needs to search up to 32 tiles around itself, i.e. 64
|
||||
by 64 tiles, to find all possible stations it could deliver to
|
||||
instead of 10 by 10 tiles (40 times more tiles). Alternatively the
|
||||
search from a station could be changed to use the actual tiles, but
|
||||
that would require considering checking 10 by 10 tiles for each of
|
||||
the tiles of a station, instead of just once.
|
||||
|
||||
Trains might not stop at platforms that are currently being changed [FS#5553]:
|
||||
If you add tiles to or remove tiles from a platform while a train is
|
||||
approaching to stop at the same platform, that train can miss the place
|
||||
where it's supposed to stop and pass the station without stopping. This
|
||||
is caused by the fact that the train is considered to already have stopped
|
||||
if it's beyond its assigned stopping location. We can't let the train stop
|
||||
just anywhere in the station because then it would never leave the station
|
||||
if you have the same station in the order list multiple times in a row or
|
||||
if there is only one station in the order list (see FS#5684).
|
||||
|
|
32
src/gfx.cpp
32
src/gfx.cpp
|
@ -270,12 +270,12 @@ static void SetColourRemap(TextColour colour)
|
|||
* @return In case of left or center alignment the right most pixel we have drawn to.
|
||||
* In case of right alignment the left most pixel we have drawn to.
|
||||
*/
|
||||
static int DrawLayoutLine(ParagraphLayout::Line *line, int y, int left, int right, StringAlignment align, bool underline, bool truncation)
|
||||
static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left, int right, StringAlignment align, bool underline, bool truncation)
|
||||
{
|
||||
if (line->countRuns() == 0) return 0;
|
||||
if (line->CountRuns() == 0) return 0;
|
||||
|
||||
int w = line->getWidth();
|
||||
int h = line->getLeading();
|
||||
int w = line->GetWidth();
|
||||
int h = line->GetLeading();
|
||||
|
||||
/*
|
||||
* The following is needed for truncation.
|
||||
|
@ -306,7 +306,7 @@ static int DrawLayoutLine(ParagraphLayout::Line *line, int y, int left, int righ
|
|||
* another size would be chosen it won't have truncated too little for
|
||||
* the truncation dots.
|
||||
*/
|
||||
FontCache *fc = ((const Font*)line->getVisualRun(0)->getFont())->fc;
|
||||
FontCache *fc = ((const Font*)line->GetVisualRun(0)->GetFont())->fc;
|
||||
GlyphID dot_glyph = fc->MapCharToGlyph('.');
|
||||
dot_width = fc->GetGlyphWidth(dot_glyph);
|
||||
dot_sprite = fc->GetGlyph(dot_glyph);
|
||||
|
@ -349,9 +349,9 @@ static int DrawLayoutLine(ParagraphLayout::Line *line, int y, int left, int righ
|
|||
NOT_REACHED();
|
||||
}
|
||||
|
||||
for (int run_index = 0; run_index < line->countRuns(); run_index++) {
|
||||
const ParagraphLayout::VisualRun *run = line->getVisualRun(run_index);
|
||||
const Font *f = (const Font*)run->getFont();
|
||||
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
|
||||
const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index);
|
||||
const Font *f = (const Font*)run->GetFont();
|
||||
|
||||
FontCache *fc = f->fc;
|
||||
TextColour colour = f->colour;
|
||||
|
@ -363,15 +363,15 @@ static int DrawLayoutLine(ParagraphLayout::Line *line, int y, int left, int righ
|
|||
|
||||
bool draw_shadow = fc->GetDrawGlyphShadow() && colour != TC_BLACK;
|
||||
|
||||
for (int i = 0; i < run->getGlyphCount(); i++) {
|
||||
GlyphID glyph = run->getGlyphs()[i];
|
||||
for (int i = 0; i < run->GetGlyphCount(); i++) {
|
||||
GlyphID glyph = run->GetGlyphs()[i];
|
||||
|
||||
/* Not a valid glyph (empty) */
|
||||
if (glyph == 0xFFFF) continue;
|
||||
|
||||
int begin_x = run->getPositions()[i * 2] + left - offset_x;
|
||||
int end_x = run->getPositions()[i * 2 + 2] + left - offset_x - 1;
|
||||
int top = run->getPositions()[i * 2 + 1] + y;
|
||||
int begin_x = (int)run->GetPositions()[i * 2] + left - offset_x;
|
||||
int end_x = (int)run->GetPositions()[i * 2 + 2] + left - offset_x - 1;
|
||||
int top = (int)run->GetPositions()[i * 2 + 1] + y;
|
||||
|
||||
/* Truncated away. */
|
||||
if (truncation && (begin_x < min_x || end_x > max_x)) continue;
|
||||
|
@ -571,10 +571,10 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, const char *st
|
|||
int last_line = top;
|
||||
int first_line = bottom;
|
||||
|
||||
for (ParagraphLayout::Line **iter = layout.Begin(); iter != layout.End(); iter++) {
|
||||
ParagraphLayout::Line *line = *iter;
|
||||
for (const ParagraphLayouter::Line **iter = layout.Begin(); iter != layout.End(); iter++) {
|
||||
const ParagraphLayouter::Line *line = *iter;
|
||||
|
||||
int line_height = line->getLeading();
|
||||
int line_height = line->GetLeading();
|
||||
if (y >= top && y < bottom) {
|
||||
last_line = y + line_height;
|
||||
if (first_line > y) first_line = y;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "gfx_layout.h"
|
||||
#include "string_func.h"
|
||||
#include "strings_func.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "table/control_codes.h"
|
||||
|
||||
|
@ -110,7 +111,7 @@ le_bool Font::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &poin
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
size_t Layouter::AppendToBuffer(UChar *buff, const UChar *buffer_last, WChar c)
|
||||
static size_t AppendToBuffer(UChar *buff, const UChar *buffer_last, WChar c)
|
||||
{
|
||||
/* Transform from UTF-32 to internal ICU format of UTF-16. */
|
||||
int32 length = 0;
|
||||
|
@ -119,7 +120,63 @@ size_t Layouter::AppendToBuffer(UChar *buff, const UChar *buffer_last, WChar c)
|
|||
return length;
|
||||
}
|
||||
|
||||
ParagraphLayout *Layouter::GetParagraphLayout(UChar *buff, UChar *buff_end, FontMap &fontMapping)
|
||||
/**
|
||||
* Wrapper for doing layouts with ICU.
|
||||
*/
|
||||
class ICUParagraphLayout : public AutoDeleteSmallVector<ParagraphLayouter::Line *, 4>, public ParagraphLayouter {
|
||||
ParagraphLayout *p; ///< The actual ICU paragraph layout.
|
||||
public:
|
||||
/** Helper for GetLayouter, to get the right type. */
|
||||
typedef UChar CharType;
|
||||
/** Helper for GetLayouter, to get whether the layouter supports RTL. */
|
||||
static const bool SUPPORTS_RTL = true;
|
||||
|
||||
/** Visual run contains data about the bit of text with the same font. */
|
||||
class ICUVisualRun : public ParagraphLayouter::VisualRun {
|
||||
const ParagraphLayout::VisualRun *vr; ///< The actual ICU vr.
|
||||
|
||||
public:
|
||||
ICUVisualRun(const ParagraphLayout::VisualRun *vr) : vr(vr) { }
|
||||
|
||||
const Font *GetFont() const { return (const Font*)vr->getFont(); }
|
||||
int GetGlyphCount() const { return vr->getGlyphCount(); }
|
||||
const GlyphID *GetGlyphs() const { return vr->getGlyphs(); }
|
||||
const float *GetPositions() const { return vr->getPositions(); }
|
||||
int GetLeading() const { return vr->getLeading(); }
|
||||
const int *GetGlyphToCharMap() const { return vr->getGlyphToCharMap(); }
|
||||
};
|
||||
|
||||
/** A single line worth of VisualRuns. */
|
||||
class ICULine : public AutoDeleteSmallVector<ICUVisualRun *, 4>, public ParagraphLayouter::Line {
|
||||
ParagraphLayout::Line *l; ///< The actual ICU line.
|
||||
|
||||
public:
|
||||
ICULine(ParagraphLayout::Line *l) : l(l)
|
||||
{
|
||||
for (int i = 0; i < l->countRuns(); i++) {
|
||||
*this->Append() = new ICUVisualRun(l->getVisualRun(i));
|
||||
}
|
||||
}
|
||||
~ICULine() { delete l; }
|
||||
|
||||
int GetLeading() const { return l->getLeading(); }
|
||||
int GetWidth() const { return l->getWidth(); }
|
||||
int CountRuns() const { return l->countRuns(); }
|
||||
const ParagraphLayouter::VisualRun *GetVisualRun(int run) const { return *this->Get(run); }
|
||||
};
|
||||
|
||||
ICUParagraphLayout(ParagraphLayout *p) : p(p) { }
|
||||
~ICUParagraphLayout() { delete p; }
|
||||
void Reflow() { p->reflow(); }
|
||||
|
||||
ParagraphLayouter::Line *NextLine(int max_width)
|
||||
{
|
||||
ParagraphLayout::Line *l = p->nextLine(max_width);
|
||||
return l == NULL ? NULL : new ICULine(l);
|
||||
}
|
||||
};
|
||||
|
||||
static ParagraphLayouter *GetParagraphLayout(UChar *buff, UChar *buff_end, FontMap &fontMapping)
|
||||
{
|
||||
int32 length = buff_end - buff;
|
||||
|
||||
|
@ -139,12 +196,79 @@ ParagraphLayout *Layouter::GetParagraphLayout(UChar *buff, UChar *buff_end, Font
|
|||
LEErrorCode status = LE_NO_ERROR;
|
||||
/* ParagraphLayout does not copy "buff", so it must stay valid.
|
||||
* "runs" is copied according to the ICU source, but the documentation does not specify anything, so this might break somewhen. */
|
||||
return new ParagraphLayout(buff, length, &runs, NULL, NULL, NULL, _current_text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, false, status);
|
||||
ParagraphLayout *p = new ParagraphLayout(buff, length, &runs, NULL, NULL, NULL, _current_text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, false, status);
|
||||
if (status != LE_NO_ERROR) {
|
||||
delete p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new ICUParagraphLayout(p);
|
||||
}
|
||||
|
||||
#else /* WITH_ICU */
|
||||
#endif /* WITH_ICU */
|
||||
|
||||
/*** Paragraph layout ***/
|
||||
/**
|
||||
* Class handling the splitting of a paragraph of text into lines and
|
||||
* visual runs.
|
||||
*
|
||||
* One constructs this class with the text that needs to be split into
|
||||
* lines. Then nextLine is called with the maximum width until NULL is
|
||||
* returned. Each nextLine call creates VisualRuns which contain the
|
||||
* length of text that are to be drawn with the same font. In other
|
||||
* words, the result of this class is a list of sub strings with their
|
||||
* font. The sub strings are then already fully laid out, and only
|
||||
* need actual drawing.
|
||||
*
|
||||
* The positions in a visual run are sequential pairs of X,Y of the
|
||||
* begin of each of the glyphs plus an extra pair to mark the end.
|
||||
*
|
||||
* @note This variant does not handle left-to-right properly. This
|
||||
* is supported in the one ParagraphLayout coming from ICU.
|
||||
*/
|
||||
class FallbackParagraphLayout : public ParagraphLayouter {
|
||||
public:
|
||||
/** Helper for GetLayouter, to get the right type. */
|
||||
typedef WChar CharType;
|
||||
/** Helper for GetLayouter, to get whether the layouter supports RTL. */
|
||||
static const bool SUPPORTS_RTL = false;
|
||||
|
||||
/** Visual run contains data about the bit of text with the same font. */
|
||||
class FallbackVisualRun : public ParagraphLayouter::VisualRun {
|
||||
Font *font; ///< The font used to layout these.
|
||||
GlyphID *glyphs; ///< The glyphs we're drawing.
|
||||
float *positions; ///< The positions of the glyphs.
|
||||
int *glyph_to_char; ///< The char index of the glyphs.
|
||||
int glyph_count; ///< The number of glyphs.
|
||||
|
||||
public:
|
||||
FallbackVisualRun(Font *font, const WChar *chars, int glyph_count, int x);
|
||||
~FallbackVisualRun();
|
||||
const Font *GetFont() const;
|
||||
int GetGlyphCount() const;
|
||||
const GlyphID *GetGlyphs() const;
|
||||
const float *GetPositions() const;
|
||||
int GetLeading() const;
|
||||
const int *GetGlyphToCharMap() const;
|
||||
};
|
||||
|
||||
/** A single line worth of VisualRuns. */
|
||||
class FallbackLine : public AutoDeleteSmallVector<FallbackVisualRun *, 4>, public ParagraphLayouter::Line {
|
||||
public:
|
||||
int GetLeading() const;
|
||||
int GetWidth() const;
|
||||
int CountRuns() const;
|
||||
const ParagraphLayouter::VisualRun *GetVisualRun(int run) const;
|
||||
};
|
||||
|
||||
const WChar *buffer_begin; ///< Begin of the buffer.
|
||||
const WChar *buffer; ///< The current location in the buffer.
|
||||
FontMap &runs; ///< The fonts we have to use for this paragraph.
|
||||
|
||||
FallbackParagraphLayout(WChar *buffer, int length, FontMap &runs);
|
||||
void Reflow();
|
||||
const ParagraphLayouter::Line *NextLine(int max_width);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the visual run.
|
||||
|
@ -153,7 +277,7 @@ ParagraphLayout *Layouter::GetParagraphLayout(UChar *buff, UChar *buff_end, Font
|
|||
* @param char_count The number of characters in this run.
|
||||
* @param x The initial x position for this run.
|
||||
*/
|
||||
ParagraphLayout::VisualRun::VisualRun(Font *font, const WChar *chars, int char_count, int x) :
|
||||
FallbackParagraphLayout::FallbackVisualRun::FallbackVisualRun(Font *font, const WChar *chars, int char_count, int x) :
|
||||
font(font), glyph_count(char_count)
|
||||
{
|
||||
this->glyphs = MallocT<GlyphID>(this->glyph_count);
|
||||
|
@ -173,7 +297,7 @@ ParagraphLayout::VisualRun::VisualRun(Font *font, const WChar *chars, int char_c
|
|||
}
|
||||
|
||||
/** Free all data. */
|
||||
ParagraphLayout::VisualRun::~VisualRun()
|
||||
FallbackParagraphLayout::FallbackVisualRun::~FallbackVisualRun()
|
||||
{
|
||||
free(this->positions);
|
||||
free(this->glyph_to_char);
|
||||
|
@ -184,7 +308,7 @@ ParagraphLayout::VisualRun::~VisualRun()
|
|||
* Get the font associated with this run.
|
||||
* @return The font.
|
||||
*/
|
||||
Font *ParagraphLayout::VisualRun::getFont() const
|
||||
const Font *FallbackParagraphLayout::FallbackVisualRun::GetFont() const
|
||||
{
|
||||
return this->font;
|
||||
}
|
||||
|
@ -193,7 +317,7 @@ Font *ParagraphLayout::VisualRun::getFont() const
|
|||
* Get the number of glyhps in this run.
|
||||
* @return The number of glyphs.
|
||||
*/
|
||||
int ParagraphLayout::VisualRun::getGlyphCount() const
|
||||
int FallbackParagraphLayout::FallbackVisualRun::GetGlyphCount() const
|
||||
{
|
||||
return this->glyph_count;
|
||||
}
|
||||
|
@ -202,7 +326,7 @@ int ParagraphLayout::VisualRun::getGlyphCount() const
|
|||
* Get the glyhps of this run.
|
||||
* @return The glyphs.
|
||||
*/
|
||||
const GlyphID *ParagraphLayout::VisualRun::getGlyphs() const
|
||||
const GlyphID *FallbackParagraphLayout::FallbackVisualRun::GetGlyphs() const
|
||||
{
|
||||
return this->glyphs;
|
||||
}
|
||||
|
@ -211,7 +335,7 @@ const GlyphID *ParagraphLayout::VisualRun::getGlyphs() const
|
|||
* Get the positions of this run.
|
||||
* @return The positions.
|
||||
*/
|
||||
float *ParagraphLayout::VisualRun::getPositions() const
|
||||
const float *FallbackParagraphLayout::FallbackVisualRun::GetPositions() const
|
||||
{
|
||||
return this->positions;
|
||||
}
|
||||
|
@ -220,7 +344,7 @@ float *ParagraphLayout::VisualRun::getPositions() const
|
|||
* Get the glyph-to-character map for this visual run.
|
||||
* @return The glyph-to-character map.
|
||||
*/
|
||||
const int *ParagraphLayout::VisualRun::getGlyphToCharMap() const
|
||||
const int *FallbackParagraphLayout::FallbackVisualRun::GetGlyphToCharMap() const
|
||||
{
|
||||
return this->glyph_to_char;
|
||||
}
|
||||
|
@ -229,20 +353,20 @@ const int *ParagraphLayout::VisualRun::getGlyphToCharMap() const
|
|||
* Get the height of this font.
|
||||
* @return The height of the font.
|
||||
*/
|
||||
int ParagraphLayout::VisualRun::getLeading() const
|
||||
int FallbackParagraphLayout::FallbackVisualRun::GetLeading() const
|
||||
{
|
||||
return this->getFont()->fc->GetHeight();
|
||||
return this->GetFont()->fc->GetHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of the line.
|
||||
* @return The maximum height of the line.
|
||||
*/
|
||||
int ParagraphLayout::Line::getLeading() const
|
||||
int FallbackParagraphLayout::FallbackLine::GetLeading() const
|
||||
{
|
||||
int leading = 0;
|
||||
for (const VisualRun * const *run = this->Begin(); run != this->End(); run++) {
|
||||
leading = max(leading, (*run)->getLeading());
|
||||
for (const FallbackVisualRun * const *run = this->Begin(); run != this->End(); run++) {
|
||||
leading = max(leading, (*run)->GetLeading());
|
||||
}
|
||||
|
||||
return leading;
|
||||
|
@ -252,7 +376,7 @@ int ParagraphLayout::Line::getLeading() const
|
|||
* Get the width of this line.
|
||||
* @return The width of the line.
|
||||
*/
|
||||
int ParagraphLayout::Line::getWidth() const
|
||||
int FallbackParagraphLayout::FallbackLine::GetWidth() const
|
||||
{
|
||||
if (this->Length() == 0) return 0;
|
||||
|
||||
|
@ -261,15 +385,15 @@ int ParagraphLayout::Line::getWidth() const
|
|||
* Since there is no left-to-right support, taking this value of
|
||||
* the last run gives us the end of the line and thus the width.
|
||||
*/
|
||||
const VisualRun *run = this->getVisualRun(this->countRuns() - 1);
|
||||
return run->getPositions()[run->getGlyphCount() * 2];
|
||||
const ParagraphLayouter::VisualRun *run = this->GetVisualRun(this->CountRuns() - 1);
|
||||
return (int)run->GetPositions()[run->GetGlyphCount() * 2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of runs in this line.
|
||||
* @return The number of runs.
|
||||
*/
|
||||
int ParagraphLayout::Line::countRuns() const
|
||||
int FallbackParagraphLayout::FallbackLine::CountRuns() const
|
||||
{
|
||||
return this->Length();
|
||||
}
|
||||
|
@ -278,7 +402,7 @@ int ParagraphLayout::Line::countRuns() const
|
|||
* Get a specific visual run.
|
||||
* @return The visual run.
|
||||
*/
|
||||
ParagraphLayout::VisualRun *ParagraphLayout::Line::getVisualRun(int run) const
|
||||
const ParagraphLayouter::VisualRun *FallbackParagraphLayout::FallbackLine::GetVisualRun(int run) const
|
||||
{
|
||||
return *this->Get(run);
|
||||
}
|
||||
|
@ -289,7 +413,7 @@ ParagraphLayout::VisualRun *ParagraphLayout::Line::getVisualRun(int run) const
|
|||
* @param length The length of the paragraph.
|
||||
* @param runs The font mapping of this paragraph.
|
||||
*/
|
||||
ParagraphLayout::ParagraphLayout(WChar *buffer, int length, FontMap &runs) : buffer_begin(buffer), buffer(buffer), runs(runs)
|
||||
FallbackParagraphLayout::FallbackParagraphLayout(WChar *buffer, int length, FontMap &runs) : buffer_begin(buffer), buffer(buffer), runs(runs)
|
||||
{
|
||||
assert(runs.End()[-1].first == length);
|
||||
}
|
||||
|
@ -297,7 +421,7 @@ ParagraphLayout::ParagraphLayout(WChar *buffer, int length, FontMap &runs) : buf
|
|||
/**
|
||||
* Reset the position to the start of the paragraph.
|
||||
*/
|
||||
void ParagraphLayout::reflow()
|
||||
void FallbackParagraphLayout::Reflow()
|
||||
{
|
||||
this->buffer = this->buffer_begin;
|
||||
}
|
||||
|
@ -307,7 +431,7 @@ void ParagraphLayout::reflow()
|
|||
* @param max_width The maximum width of the string.
|
||||
* @return A Line, or NULL when at the end of the paragraph.
|
||||
*/
|
||||
ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
|
||||
const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width)
|
||||
{
|
||||
/* Simple idea:
|
||||
* - split a line at a newline character, or at a space where we can break a line.
|
||||
|
@ -315,12 +439,12 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
|
|||
*/
|
||||
if (this->buffer == NULL) return NULL;
|
||||
|
||||
Line *l = new Line();
|
||||
FallbackLine *l = new FallbackLine();
|
||||
|
||||
if (*this->buffer == '\0') {
|
||||
/* Only a newline. */
|
||||
this->buffer = NULL;
|
||||
*l->Append() = new VisualRun(this->runs.Begin()->second, this->buffer, 0, 0);
|
||||
*l->Append() = new FallbackVisualRun(this->runs.Begin()->second, this->buffer, 0, 0);
|
||||
return l;
|
||||
}
|
||||
|
||||
|
@ -349,8 +473,8 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
|
|||
}
|
||||
|
||||
if (this->buffer == next_run) {
|
||||
int w = l->getWidth();
|
||||
*l->Append() = new VisualRun(iter->second, begin, this->buffer - begin, w);
|
||||
int w = l->GetWidth();
|
||||
*l->Append() = new FallbackVisualRun(iter->second, begin, this->buffer - begin, w);
|
||||
iter++;
|
||||
assert(iter != this->runs.End());
|
||||
|
||||
|
@ -396,8 +520,8 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
|
|||
}
|
||||
|
||||
if (l->Length() == 0 || last_char - begin != 0) {
|
||||
int w = l->getWidth();
|
||||
*l->Append() = new VisualRun(iter->second, begin, last_char - begin, w);
|
||||
int w = l->GetWidth();
|
||||
*l->Append() = new FallbackVisualRun(iter->second, begin, last_char - begin, w);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
@ -409,7 +533,7 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
|
|||
* @param c The character to add.
|
||||
* @return The number of buffer spaces that were used.
|
||||
*/
|
||||
size_t Layouter::AppendToBuffer(WChar *buff, const WChar *buffer_last, WChar c)
|
||||
static size_t AppendToBuffer(WChar *buff, const WChar *buffer_last, WChar c)
|
||||
{
|
||||
*buff = c;
|
||||
return 1;
|
||||
|
@ -422,11 +546,74 @@ size_t Layouter::AppendToBuffer(WChar *buff, const WChar *buffer_last, WChar c)
|
|||
* @param fontMapping THe mapping of the fonts.
|
||||
* @return The ParagraphLayout instance.
|
||||
*/
|
||||
ParagraphLayout *Layouter::GetParagraphLayout(WChar *buff, WChar *buff_end, FontMap &fontMapping)
|
||||
static FallbackParagraphLayout *GetParagraphLayout(WChar *buff, WChar *buff_end, FontMap &fontMapping)
|
||||
{
|
||||
return new ParagraphLayout(buff, buff_end - buff, fontMapping);
|
||||
return new FallbackParagraphLayout(buff, buff_end - buff, fontMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for getting a ParagraphLayouter of the given type.
|
||||
*
|
||||
* @note In case no ParagraphLayouter could be constructed, line.layout will be NULL.
|
||||
* @param line The cache item to store our layouter in.
|
||||
* @param str The string to create a layouter for.
|
||||
* @param state The state of the font and color.
|
||||
* @tparam T The type of layouter we want.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline void GetLayouter(Layouter::LineCacheItem &line, const char *str, FontState state)
|
||||
{
|
||||
if (line.buffer != NULL) free(line.buffer);
|
||||
|
||||
typename T::CharType *buff_begin = MallocT<typename T::CharType>(DRAW_STRING_BUFFER);
|
||||
const typename T::CharType *buffer_last = buff_begin + DRAW_STRING_BUFFER;
|
||||
typename T::CharType *buff = buff_begin;
|
||||
FontMap &fontMapping = line.runs;
|
||||
Font *f = Layouter::GetFont(state.fontsize, state.cur_colour);
|
||||
|
||||
line.buffer = buff_begin;
|
||||
|
||||
/*
|
||||
* 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' || c == '\n') {
|
||||
break;
|
||||
} else if (c >= SCC_BLUE && c <= SCC_BLACK) {
|
||||
state.SetColour((TextColour)(c - SCC_BLUE));
|
||||
} else if (c == SCC_PREVIOUS_COLOUR) { // Revert to the previous colour.
|
||||
state.SetPreviousColour();
|
||||
} else if (c == SCC_TINYFONT) {
|
||||
state.SetFontSize(FS_SMALL);
|
||||
} else if (c == SCC_BIGFONT) {
|
||||
state.SetFontSize(FS_LARGE);
|
||||
} else {
|
||||
/* Filter out text direction characters that shouldn't be drawn, and
|
||||
* will not be handled in the fallback non ICU case because they are
|
||||
* mostly needed for RTL languages which need more ICU support. */
|
||||
if (!T::SUPPORTS_RTL && IsTextDirectionChar(c)) continue;
|
||||
buff += AppendToBuffer(buff, buffer_last, c);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fontMapping.Contains(buff - buff_begin)) {
|
||||
fontMapping.Insert(buff - buff_begin, f);
|
||||
}
|
||||
f = Layouter::GetFont(state.fontsize, state.cur_colour);
|
||||
}
|
||||
|
||||
/* Better safe than sorry. */
|
||||
*buff = '\0';
|
||||
|
||||
if (!fontMapping.Contains(buff - buff_begin)) {
|
||||
fontMapping.Insert(buff - buff_begin, f);
|
||||
}
|
||||
line.layout = GetParagraphLayout(buff_begin, buff, fontMapping);
|
||||
line.state_after = state;
|
||||
}
|
||||
#endif /* !WITH_ICU */
|
||||
|
||||
/**
|
||||
* Create a new layouter.
|
||||
|
@ -454,62 +641,27 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi
|
|||
/* Line is in cache */
|
||||
str = lineend + 1;
|
||||
state = line.state_after;
|
||||
line.layout->reflow();
|
||||
line.layout->Reflow();
|
||||
} else {
|
||||
/* Line is new, layout it */
|
||||
const CharType *buffer_last = lastof(line.buffer);
|
||||
CharType *buff_begin = line.buffer;
|
||||
CharType *buff = buff_begin;
|
||||
FontMap &fontMapping = line.runs;
|
||||
Font *f = GetFont(state.fontsize, state.cur_colour);
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
state.SetColour((TextColour)(c - SCC_BLUE));
|
||||
} else if (c == SCC_PREVIOUS_COLOUR) { // Revert to the previous colour.
|
||||
state.SetPreviousColour();
|
||||
} else if (c == SCC_TINYFONT) {
|
||||
state.SetFontSize(FS_SMALL);
|
||||
} else if (c == SCC_BIGFONT) {
|
||||
state.SetFontSize(FS_LARGE);
|
||||
} else {
|
||||
#ifndef WITH_ICU
|
||||
/* Filter out text direction characters that shouldn't be drawn, and
|
||||
* will not be handled in the fallback non ICU case because they are
|
||||
* mostly needed for RTL languages which need more ICU support. */
|
||||
if (IsTextDirectionChar(c)) continue;
|
||||
#ifdef WITH_ICU
|
||||
GetLayouter<ICUParagraphLayout>(line, str, state);
|
||||
if (line.layout == NULL) {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
DEBUG(misc, 0, "ICU layouter bailed on the font. Falling back to the fallback layouter");
|
||||
warned = true;
|
||||
}
|
||||
GetLayouter<FallbackParagraphLayout>(line, str, state);
|
||||
}
|
||||
#else
|
||||
GetLayouter<FallbackParagraphLayout>(line, str, state);
|
||||
#endif
|
||||
buff += AppendToBuffer(buff, buffer_last, c);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fontMapping.Contains(buff - buff_begin)) {
|
||||
fontMapping.Insert(buff - buff_begin, f);
|
||||
}
|
||||
f = GetFont(state.fontsize, state.cur_colour);
|
||||
}
|
||||
|
||||
/* Better safe than sorry. */
|
||||
*buff = '\0';
|
||||
|
||||
if (!fontMapping.Contains(buff - buff_begin)) {
|
||||
fontMapping.Insert(buff - buff_begin, f);
|
||||
}
|
||||
line.layout = GetParagraphLayout(buff_begin, buff, fontMapping);
|
||||
line.state_after = state;
|
||||
}
|
||||
|
||||
/* Copy all lines into a local cache so we can reuse them later on more easily. */
|
||||
ParagraphLayout::Line *l;
|
||||
while ((l = line.layout->nextLine(maxw)) != NULL) {
|
||||
const ParagraphLayouter::Line *l;
|
||||
while ((l = line.layout->NextLine(maxw)) != NULL) {
|
||||
*this->Append() = l;
|
||||
}
|
||||
|
||||
|
@ -523,9 +675,9 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi
|
|||
Dimension Layouter::GetBounds()
|
||||
{
|
||||
Dimension d = { 0, 0 };
|
||||
for (ParagraphLayout::Line **l = this->Begin(); l != this->End(); l++) {
|
||||
d.width = max<uint>(d.width, (*l)->getWidth());
|
||||
d.height += (*l)->getLeading();
|
||||
for (const ParagraphLayouter::Line **l = this->Begin(); l != this->End(); l++) {
|
||||
d.width = max<uint>(d.width, (*l)->GetWidth());
|
||||
d.height += (*l)->GetLeading();
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
@ -557,22 +709,22 @@ Point Layouter::GetCharPosition(const char *ch) const
|
|||
|
||||
if (str == ch) {
|
||||
/* Valid character. */
|
||||
const ParagraphLayout::Line *line = *this->Begin();
|
||||
const ParagraphLayouter::Line *line = *this->Begin();
|
||||
|
||||
/* Pointer to the end-of-string/line marker? Return total line width. */
|
||||
if (*ch == '\0' || *ch == '\n') {
|
||||
Point p = { line->getWidth(), 0 };
|
||||
Point p = { line->GetWidth(), 0 };
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Scan all runs until we've found our code point index. */
|
||||
for (int run_index = 0; run_index < line->countRuns(); run_index++) {
|
||||
const ParagraphLayout::VisualRun *run = line->getVisualRun(run_index);
|
||||
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
|
||||
const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index);
|
||||
|
||||
for (int i = 0; i < run->getGlyphCount(); i++) {
|
||||
for (int i = 0; i < run->GetGlyphCount(); i++) {
|
||||
/* Matching glyph? Return position. */
|
||||
if ((size_t)run->getGlyphToCharMap()[i] == index) {
|
||||
Point p = { (int)run->getPositions()[i * 2], (int)run->getPositions()[i * 2 + 1] };
|
||||
if ((size_t)run->GetGlyphToCharMap()[i] == index) {
|
||||
Point p = { (int)run->GetPositions()[i * 2], (int)run->GetPositions()[i * 2 + 1] };
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,84 +97,47 @@ public:
|
|||
/** Mapping from index to font. */
|
||||
typedef SmallMap<int, Font *> FontMap;
|
||||
|
||||
#ifndef WITH_ICU
|
||||
/**
|
||||
* Class handling the splitting of a paragraph of text into lines and
|
||||
* visual runs.
|
||||
*
|
||||
* One constructs this class with the text that needs to be split into
|
||||
* lines. Then nextLine is called with the maximum width until NULL is
|
||||
* returned. Each nextLine call creates VisualRuns which contain the
|
||||
* length of text that are to be drawn with the same font. In other
|
||||
* words, the result of this class is a list of sub strings with their
|
||||
* font. The sub strings are then already fully laid out, and only
|
||||
* need actual drawing.
|
||||
*
|
||||
* The positions in a visual run are sequential pairs of X,Y of the
|
||||
* begin of each of the glyphs plus an extra pair to mark the end.
|
||||
*
|
||||
* @note This variant does not handle left-to-right properly. This
|
||||
* is supported in the one ParagraphLayout coming from ICU.
|
||||
* @note Does not conform to function naming style as it provides a
|
||||
* fallback for the ICU class.
|
||||
* Interface to glue fallback and normal layouter into one.
|
||||
*/
|
||||
class ParagraphLayout {
|
||||
class ParagraphLayouter {
|
||||
public:
|
||||
virtual ~ParagraphLayouter() {}
|
||||
|
||||
/** Visual run contains data about the bit of text with the same font. */
|
||||
class VisualRun {
|
||||
Font *font; ///< The font used to layout these.
|
||||
GlyphID *glyphs; ///< The glyphs we're drawing.
|
||||
float *positions; ///< The positions of the glyphs.
|
||||
int *glyph_to_char; ///< The char index of the glyphs.
|
||||
int glyph_count; ///< The number of glyphs.
|
||||
|
||||
public:
|
||||
VisualRun(Font *font, const WChar *chars, int glyph_count, int x);
|
||||
~VisualRun();
|
||||
Font *getFont() const;
|
||||
int getGlyphCount() const;
|
||||
const GlyphID *getGlyphs() const;
|
||||
float *getPositions() const;
|
||||
int getLeading() const;
|
||||
const int *getGlyphToCharMap() const;
|
||||
virtual ~VisualRun() {}
|
||||
virtual const Font *GetFont() const = 0;
|
||||
virtual int GetGlyphCount() const = 0;
|
||||
virtual const GlyphID *GetGlyphs() const = 0;
|
||||
virtual const float *GetPositions() const = 0;
|
||||
virtual int GetLeading() const = 0;
|
||||
virtual const int *GetGlyphToCharMap() const = 0;
|
||||
};
|
||||
|
||||
/** A single line worth of VisualRuns. */
|
||||
class Line : public AutoDeleteSmallVector<VisualRun *, 4> {
|
||||
class Line {
|
||||
public:
|
||||
int getLeading() const;
|
||||
int getWidth() const;
|
||||
int countRuns() const;
|
||||
VisualRun *getVisualRun(int run) const;
|
||||
virtual ~Line() {}
|
||||
virtual int GetLeading() const = 0;
|
||||
virtual int GetWidth() const = 0;
|
||||
virtual int CountRuns() const = 0;
|
||||
virtual const VisualRun *GetVisualRun(int run) const = 0;
|
||||
};
|
||||
|
||||
const WChar *buffer_begin; ///< Begin of the buffer.
|
||||
const WChar *buffer; ///< The current location in the buffer.
|
||||
FontMap &runs; ///< The fonts we have to use for this paragraph.
|
||||
|
||||
ParagraphLayout(WChar *buffer, int length, FontMap &runs);
|
||||
void reflow();
|
||||
Line *nextLine(int max_width);
|
||||
virtual void Reflow() = 0;
|
||||
virtual const Line *NextLine(int max_width) = 0;
|
||||
};
|
||||
#endif /* !WITH_ICU */
|
||||
|
||||
/**
|
||||
* The layouter performs all the layout work.
|
||||
*
|
||||
* It also accounts for the memory allocations and frees.
|
||||
*/
|
||||
class Layouter : public AutoDeleteSmallVector<ParagraphLayout::Line *, 4> {
|
||||
#ifdef WITH_ICU
|
||||
typedef UChar CharType; ///< The type of character used within the layouter.
|
||||
#else /* WITH_ICU */
|
||||
typedef WChar CharType; ///< The type of character used within the layouter.
|
||||
#endif /* WITH_ICU */
|
||||
|
||||
class Layouter : public AutoDeleteSmallVector<const ParagraphLayouter::Line *, 4> {
|
||||
const char *string; ///< Pointer to the original string.
|
||||
|
||||
size_t AppendToBuffer(CharType *buff, const CharType *buffer_last, WChar c);
|
||||
ParagraphLayout *GetParagraphLayout(CharType *buff, CharType *buff_end, FontMap &fontMapping);
|
||||
|
||||
/** Key into the linecache */
|
||||
struct LineCacheKey {
|
||||
FontState state_before; ///< Font state at the beginning of the line.
|
||||
|
@ -189,18 +152,20 @@ class Layouter : public AutoDeleteSmallVector<ParagraphLayout::Line *, 4> {
|
|||
return this->str < other.str;
|
||||
}
|
||||
};
|
||||
public:
|
||||
/** Item in the linecache */
|
||||
struct LineCacheItem {
|
||||
/* Stuff that cannot be freed until the ParagraphLayout is freed */
|
||||
CharType buffer[DRAW_STRING_BUFFER]; ///< Accessed by both ICU's and our ParagraphLayout::nextLine.
|
||||
FontMap runs; ///< Accessed by our ParagraphLayout::nextLine.
|
||||
void *buffer; ///< Accessed by both ICU's and our ParagraphLayout::nextLine.
|
||||
FontMap runs; ///< Accessed by our ParagraphLayout::nextLine.
|
||||
|
||||
FontState state_after; ///< Font state after the line.
|
||||
ParagraphLayout *layout; ///< Layout of the line.
|
||||
FontState state_after; ///< Font state after the line.
|
||||
ParagraphLayouter *layout; ///< Layout of the line.
|
||||
|
||||
LineCacheItem() : layout(NULL) {}
|
||||
~LineCacheItem() { delete layout; }
|
||||
LineCacheItem() : buffer(NULL), layout(NULL) {}
|
||||
~LineCacheItem() { delete layout; free(buffer); }
|
||||
};
|
||||
private:
|
||||
typedef std::map<LineCacheKey, LineCacheItem> LineCache;
|
||||
static LineCache *linecache;
|
||||
|
||||
|
@ -208,9 +173,9 @@ class Layouter : public AutoDeleteSmallVector<ParagraphLayout::Line *, 4> {
|
|||
|
||||
typedef SmallMap<TextColour, Font *> FontColourMap;
|
||||
static FontColourMap fonts[FS_END];
|
||||
public:
|
||||
static Font *GetFont(FontSize size, TextColour colour);
|
||||
|
||||
public:
|
||||
Layouter(const char *str, int maxw = INT32_MAX, TextColour colour = TC_FROMSTRING, FontSize fontsize = FS_NORMAL);
|
||||
Dimension GetBounds();
|
||||
Point GetCharPosition(const char *ch) const;
|
||||
|
|
|
@ -127,7 +127,8 @@ public:
|
|||
|
||||
/**
|
||||
* Import a library.
|
||||
* @param library The name of the library to import.
|
||||
* @param library The name of the library to import. The name should be composed as ScriptInfo::GetCategory() + "." +
|
||||
* ScriptInfo::CreateInstance().
|
||||
* @param class_name Under which name you want it to be available (or "" if you just want the returning object).
|
||||
* @param version Which version you want specifically.
|
||||
* @return The loaded library object. If class_name is set, it is also available (under the scope of the import) under that name.
|
||||
|
|
|
@ -18,9 +18,10 @@
|
|||
* Scripts must or can implemented to provide information to OpenTTD to
|
||||
* base configuring/starting/loading the Script on.
|
||||
*
|
||||
* @note The required functions are also needed for Script Libraries. As such
|
||||
* the information here can be used for libraries, but the information
|
||||
* will not be shown in the GUI except for error/debug messages.
|
||||
* @note The required functions are also needed for Script Libraries, but in
|
||||
* that case you extend ScriptLibrary. As such the information here can
|
||||
* be used for libraries, but the information will not be shown in the
|
||||
* GUI except for error/debug messages.
|
||||
*
|
||||
* @api ai game
|
||||
*/
|
||||
|
@ -43,6 +44,8 @@ public:
|
|||
*
|
||||
* @return The name of the Script.
|
||||
* @note This function is required.
|
||||
* @note This name is not used as library name by ScriptController::Import,
|
||||
* instead the name returned by #CreateInstance is used.
|
||||
*/
|
||||
string GetName();
|
||||
|
||||
|
@ -144,7 +147,8 @@ public:
|
|||
|
||||
/**
|
||||
* Gets the name of main class of the Script so OpenTTD knows
|
||||
* what class to instantiate.
|
||||
* what class to instantiate. For libraries, this name is also
|
||||
* used when other scripts import it using @ScriptController::Import.
|
||||
*
|
||||
* @return The class name of the Script.
|
||||
* @note This function is required.
|
||||
|
|
|
@ -3131,11 +3131,13 @@ static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, i
|
|||
if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
|
||||
stop &= TILE_SIZE - 1;
|
||||
|
||||
if (x >= stop) return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
|
||||
|
||||
v->vehstatus |= VS_TRAIN_SLOWING;
|
||||
uint16 spd = max(0, (stop - x) * 20 - 15);
|
||||
if (spd < v->cur_speed) v->cur_speed = spd;
|
||||
if (x == stop) {
|
||||
return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
|
||||
} else if (x < stop) {
|
||||
v->vehstatus |= VS_TRAIN_SLOWING;
|
||||
uint16 spd = max(0, (stop - x) * 20 - 15);
|
||||
if (spd < v->cur_speed) v->cur_speed = spd;
|
||||
}
|
||||
}
|
||||
} else if (v->type == VEH_ROAD) {
|
||||
RoadVehicle *rv = RoadVehicle::From(v);
|
||||
|
|
Loading…
Reference in New Issue