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-cocoa enables COCOA video driver (OSX ONLY)"
|
||||||
echo " --with-sdl[=sdl-config] enables SDL video driver support"
|
echo " --with-sdl[=sdl-config] enables SDL video driver support"
|
||||||
echo " --with-zlib[=zlib.a] enables zlib 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-liblzo2[=liblzo2.a] enables liblzo2 support"
|
||||||
echo " --with-png[=libpng-config] enables libpng support"
|
echo " --with-png[=libpng-config] enables libpng support"
|
||||||
echo " --with-freetype[=freetype-config]"
|
echo " --with-freetype[=freetype-config]"
|
||||||
echo " enables libfreetype support"
|
echo " enables libfreetype support"
|
||||||
echo " --with-fontconfig[=pkg-config fontconfig]"
|
echo " --with-fontconfig[=\"pkg-config fontconfig\"]"
|
||||||
echo " enables fontconfig support"
|
echo " enables fontconfig support"
|
||||||
echo " --with-icu[=icu-config] enables icu (used for right-to-left support)"
|
echo " --with-icu[=icu-config] enables icu (used for right-to-left support)"
|
||||||
echo " --static-icu try to link statically (libsicu instead of"
|
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
|
We cannot fix this problem as SDL simply does not provide the
|
||||||
required information in these corner cases. This is a bug in SDL
|
required information in these corner cases. This is a bug in SDL
|
||||||
and as such there is little that we can do about it.
|
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.
|
* @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.
|
* 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 w = line->GetWidth();
|
||||||
int h = line->getLeading();
|
int h = line->GetLeading();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following is needed for truncation.
|
* 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
|
* another size would be chosen it won't have truncated too little for
|
||||||
* the truncation dots.
|
* 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('.');
|
GlyphID dot_glyph = fc->MapCharToGlyph('.');
|
||||||
dot_width = fc->GetGlyphWidth(dot_glyph);
|
dot_width = fc->GetGlyphWidth(dot_glyph);
|
||||||
dot_sprite = fc->GetGlyph(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();
|
NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int run_index = 0; run_index < line->countRuns(); run_index++) {
|
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
|
||||||
const ParagraphLayout::VisualRun *run = line->getVisualRun(run_index);
|
const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index);
|
||||||
const Font *f = (const Font*)run->getFont();
|
const Font *f = (const Font*)run->GetFont();
|
||||||
|
|
||||||
FontCache *fc = f->fc;
|
FontCache *fc = f->fc;
|
||||||
TextColour colour = f->colour;
|
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;
|
bool draw_shadow = fc->GetDrawGlyphShadow() && colour != TC_BLACK;
|
||||||
|
|
||||||
for (int i = 0; i < run->getGlyphCount(); i++) {
|
for (int i = 0; i < run->GetGlyphCount(); i++) {
|
||||||
GlyphID glyph = run->getGlyphs()[i];
|
GlyphID glyph = run->GetGlyphs()[i];
|
||||||
|
|
||||||
/* Not a valid glyph (empty) */
|
/* Not a valid glyph (empty) */
|
||||||
if (glyph == 0xFFFF) continue;
|
if (glyph == 0xFFFF) continue;
|
||||||
|
|
||||||
int begin_x = run->getPositions()[i * 2] + left - offset_x;
|
int begin_x = (int)run->GetPositions()[i * 2] + left - offset_x;
|
||||||
int end_x = run->getPositions()[i * 2 + 2] + left - offset_x - 1;
|
int end_x = (int)run->GetPositions()[i * 2 + 2] + left - offset_x - 1;
|
||||||
int top = run->getPositions()[i * 2 + 1] + y;
|
int top = (int)run->GetPositions()[i * 2 + 1] + y;
|
||||||
|
|
||||||
/* Truncated away. */
|
/* Truncated away. */
|
||||||
if (truncation && (begin_x < min_x || end_x > max_x)) continue;
|
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 last_line = top;
|
||||||
int first_line = bottom;
|
int first_line = bottom;
|
||||||
|
|
||||||
for (ParagraphLayout::Line **iter = layout.Begin(); iter != layout.End(); iter++) {
|
for (const ParagraphLayouter::Line **iter = layout.Begin(); iter != layout.End(); iter++) {
|
||||||
ParagraphLayout::Line *line = *iter;
|
const ParagraphLayouter::Line *line = *iter;
|
||||||
|
|
||||||
int line_height = line->getLeading();
|
int line_height = line->GetLeading();
|
||||||
if (y >= top && y < bottom) {
|
if (y >= top && y < bottom) {
|
||||||
last_line = y + line_height;
|
last_line = y + line_height;
|
||||||
if (first_line > y) first_line = y;
|
if (first_line > y) first_line = y;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "gfx_layout.h"
|
#include "gfx_layout.h"
|
||||||
#include "string_func.h"
|
#include "string_func.h"
|
||||||
#include "strings_func.h"
|
#include "strings_func.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
#include "table/control_codes.h"
|
#include "table/control_codes.h"
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ le_bool Font::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &poin
|
||||||
return FALSE;
|
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. */
|
/* Transform from UTF-32 to internal ICU format of UTF-16. */
|
||||||
int32 length = 0;
|
int32 length = 0;
|
||||||
|
@ -119,7 +120,63 @@ size_t Layouter::AppendToBuffer(UChar *buff, const UChar *buffer_last, WChar c)
|
||||||
return length;
|
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;
|
int32 length = buff_end - buff;
|
||||||
|
|
||||||
|
@ -139,12 +196,79 @@ ParagraphLayout *Layouter::GetParagraphLayout(UChar *buff, UChar *buff_end, Font
|
||||||
LEErrorCode status = LE_NO_ERROR;
|
LEErrorCode status = LE_NO_ERROR;
|
||||||
/* ParagraphLayout does not copy "buff", so it must stay valid.
|
/* 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. */
|
* "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 ***/
|
/*** 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.
|
* 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 char_count The number of characters in this run.
|
||||||
* @param x The initial x position for 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)
|
font(font), glyph_count(char_count)
|
||||||
{
|
{
|
||||||
this->glyphs = MallocT<GlyphID>(this->glyph_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. */
|
/** Free all data. */
|
||||||
ParagraphLayout::VisualRun::~VisualRun()
|
FallbackParagraphLayout::FallbackVisualRun::~FallbackVisualRun()
|
||||||
{
|
{
|
||||||
free(this->positions);
|
free(this->positions);
|
||||||
free(this->glyph_to_char);
|
free(this->glyph_to_char);
|
||||||
|
@ -184,7 +308,7 @@ ParagraphLayout::VisualRun::~VisualRun()
|
||||||
* Get the font associated with this run.
|
* Get the font associated with this run.
|
||||||
* @return The font.
|
* @return The font.
|
||||||
*/
|
*/
|
||||||
Font *ParagraphLayout::VisualRun::getFont() const
|
const Font *FallbackParagraphLayout::FallbackVisualRun::GetFont() const
|
||||||
{
|
{
|
||||||
return this->font;
|
return this->font;
|
||||||
}
|
}
|
||||||
|
@ -193,7 +317,7 @@ Font *ParagraphLayout::VisualRun::getFont() const
|
||||||
* Get the number of glyhps in this run.
|
* Get the number of glyhps in this run.
|
||||||
* @return The number of glyphs.
|
* @return The number of glyphs.
|
||||||
*/
|
*/
|
||||||
int ParagraphLayout::VisualRun::getGlyphCount() const
|
int FallbackParagraphLayout::FallbackVisualRun::GetGlyphCount() const
|
||||||
{
|
{
|
||||||
return this->glyph_count;
|
return this->glyph_count;
|
||||||
}
|
}
|
||||||
|
@ -202,7 +326,7 @@ int ParagraphLayout::VisualRun::getGlyphCount() const
|
||||||
* Get the glyhps of this run.
|
* Get the glyhps of this run.
|
||||||
* @return The glyphs.
|
* @return The glyphs.
|
||||||
*/
|
*/
|
||||||
const GlyphID *ParagraphLayout::VisualRun::getGlyphs() const
|
const GlyphID *FallbackParagraphLayout::FallbackVisualRun::GetGlyphs() const
|
||||||
{
|
{
|
||||||
return this->glyphs;
|
return this->glyphs;
|
||||||
}
|
}
|
||||||
|
@ -211,7 +335,7 @@ const GlyphID *ParagraphLayout::VisualRun::getGlyphs() const
|
||||||
* Get the positions of this run.
|
* Get the positions of this run.
|
||||||
* @return The positions.
|
* @return The positions.
|
||||||
*/
|
*/
|
||||||
float *ParagraphLayout::VisualRun::getPositions() const
|
const float *FallbackParagraphLayout::FallbackVisualRun::GetPositions() const
|
||||||
{
|
{
|
||||||
return this->positions;
|
return this->positions;
|
||||||
}
|
}
|
||||||
|
@ -220,7 +344,7 @@ float *ParagraphLayout::VisualRun::getPositions() const
|
||||||
* Get the glyph-to-character map for this visual run.
|
* Get the glyph-to-character map for this visual run.
|
||||||
* @return The glyph-to-character map.
|
* @return The glyph-to-character map.
|
||||||
*/
|
*/
|
||||||
const int *ParagraphLayout::VisualRun::getGlyphToCharMap() const
|
const int *FallbackParagraphLayout::FallbackVisualRun::GetGlyphToCharMap() const
|
||||||
{
|
{
|
||||||
return this->glyph_to_char;
|
return this->glyph_to_char;
|
||||||
}
|
}
|
||||||
|
@ -229,20 +353,20 @@ const int *ParagraphLayout::VisualRun::getGlyphToCharMap() const
|
||||||
* Get the height of this font.
|
* Get the height of this font.
|
||||||
* @return The height of the 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.
|
* Get the height of the line.
|
||||||
* @return The maximum height of the line.
|
* @return The maximum height of the line.
|
||||||
*/
|
*/
|
||||||
int ParagraphLayout::Line::getLeading() const
|
int FallbackParagraphLayout::FallbackLine::GetLeading() const
|
||||||
{
|
{
|
||||||
int leading = 0;
|
int leading = 0;
|
||||||
for (const VisualRun * const *run = this->Begin(); run != this->End(); run++) {
|
for (const FallbackVisualRun * const *run = this->Begin(); run != this->End(); run++) {
|
||||||
leading = max(leading, (*run)->getLeading());
|
leading = max(leading, (*run)->GetLeading());
|
||||||
}
|
}
|
||||||
|
|
||||||
return leading;
|
return leading;
|
||||||
|
@ -252,7 +376,7 @@ int ParagraphLayout::Line::getLeading() const
|
||||||
* Get the width of this line.
|
* Get the width of this line.
|
||||||
* @return The width of the line.
|
* @return The width of the line.
|
||||||
*/
|
*/
|
||||||
int ParagraphLayout::Line::getWidth() const
|
int FallbackParagraphLayout::FallbackLine::GetWidth() const
|
||||||
{
|
{
|
||||||
if (this->Length() == 0) return 0;
|
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
|
* 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.
|
* the last run gives us the end of the line and thus the width.
|
||||||
*/
|
*/
|
||||||
const VisualRun *run = this->getVisualRun(this->countRuns() - 1);
|
const ParagraphLayouter::VisualRun *run = this->GetVisualRun(this->CountRuns() - 1);
|
||||||
return run->getPositions()[run->getGlyphCount() * 2];
|
return (int)run->GetPositions()[run->GetGlyphCount() * 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of runs in this line.
|
* Get the number of runs in this line.
|
||||||
* @return The number of runs.
|
* @return The number of runs.
|
||||||
*/
|
*/
|
||||||
int ParagraphLayout::Line::countRuns() const
|
int FallbackParagraphLayout::FallbackLine::CountRuns() const
|
||||||
{
|
{
|
||||||
return this->Length();
|
return this->Length();
|
||||||
}
|
}
|
||||||
|
@ -278,7 +402,7 @@ int ParagraphLayout::Line::countRuns() const
|
||||||
* Get a specific visual run.
|
* Get a specific visual run.
|
||||||
* @return The 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);
|
return *this->Get(run);
|
||||||
}
|
}
|
||||||
|
@ -289,7 +413,7 @@ ParagraphLayout::VisualRun *ParagraphLayout::Line::getVisualRun(int run) const
|
||||||
* @param length The length of the paragraph.
|
* @param length The length of the paragraph.
|
||||||
* @param runs The font mapping of this 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);
|
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.
|
* Reset the position to the start of the paragraph.
|
||||||
*/
|
*/
|
||||||
void ParagraphLayout::reflow()
|
void FallbackParagraphLayout::Reflow()
|
||||||
{
|
{
|
||||||
this->buffer = this->buffer_begin;
|
this->buffer = this->buffer_begin;
|
||||||
}
|
}
|
||||||
|
@ -307,7 +431,7 @@ void ParagraphLayout::reflow()
|
||||||
* @param max_width The maximum width of the string.
|
* @param max_width The maximum width of the string.
|
||||||
* @return A Line, or NULL when at the end of the paragraph.
|
* @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:
|
/* Simple idea:
|
||||||
* - 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.
|
||||||
|
@ -315,12 +439,12 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
|
||||||
*/
|
*/
|
||||||
if (this->buffer == NULL) return NULL;
|
if (this->buffer == NULL) return NULL;
|
||||||
|
|
||||||
Line *l = new Line();
|
FallbackLine *l = new FallbackLine();
|
||||||
|
|
||||||
if (*this->buffer == '\0') {
|
if (*this->buffer == '\0') {
|
||||||
/* Only a newline. */
|
/* Only a newline. */
|
||||||
this->buffer = NULL;
|
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;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,8 +473,8 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->buffer == next_run) {
|
if (this->buffer == next_run) {
|
||||||
int w = l->getWidth();
|
int w = l->GetWidth();
|
||||||
*l->Append() = new VisualRun(iter->second, begin, this->buffer - begin, w);
|
*l->Append() = new FallbackVisualRun(iter->second, begin, this->buffer - begin, w);
|
||||||
iter++;
|
iter++;
|
||||||
assert(iter != this->runs.End());
|
assert(iter != this->runs.End());
|
||||||
|
|
||||||
|
@ -396,8 +520,8 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->Length() == 0 || last_char - begin != 0) {
|
if (l->Length() == 0 || last_char - begin != 0) {
|
||||||
int w = l->getWidth();
|
int w = l->GetWidth();
|
||||||
*l->Append() = new VisualRun(iter->second, begin, last_char - begin, w);
|
*l->Append() = new FallbackVisualRun(iter->second, begin, last_char - begin, w);
|
||||||
}
|
}
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
@ -409,7 +533,7 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
|
||||||
* @param c The character to add.
|
* @param c The character to add.
|
||||||
* @return The number of buffer spaces that were used.
|
* @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;
|
*buff = c;
|
||||||
return 1;
|
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.
|
* @param fontMapping THe mapping of the fonts.
|
||||||
* @return The ParagraphLayout instance.
|
* @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.
|
* Create a new layouter.
|
||||||
|
@ -454,62 +641,27 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi
|
||||||
/* Line is in cache */
|
/* Line is in cache */
|
||||||
str = lineend + 1;
|
str = lineend + 1;
|
||||||
state = line.state_after;
|
state = line.state_after;
|
||||||
line.layout->reflow();
|
line.layout->Reflow();
|
||||||
} else {
|
} else {
|
||||||
/* Line is new, layout it */
|
/* Line is new, layout it */
|
||||||
const CharType *buffer_last = lastof(line.buffer);
|
#ifdef WITH_ICU
|
||||||
CharType *buff_begin = line.buffer;
|
GetLayouter<ICUParagraphLayout>(line, str, state);
|
||||||
CharType *buff = buff_begin;
|
if (line.layout == NULL) {
|
||||||
FontMap &fontMapping = line.runs;
|
static bool warned = false;
|
||||||
Font *f = GetFont(state.fontsize, state.cur_colour);
|
if (!warned) {
|
||||||
|
DEBUG(misc, 0, "ICU layouter bailed on the font. Falling back to the fallback layouter");
|
||||||
/*
|
warned = true;
|
||||||
* 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
|
GetLayouter<FallbackParagraphLayout>(line, str, state);
|
||||||
* usable by ParagraphLayout.
|
}
|
||||||
*/
|
#else
|
||||||
for (; buff < buffer_last;) {
|
GetLayouter<FallbackParagraphLayout>(line, str, state);
|
||||||
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;
|
|
||||||
#endif
|
#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. */
|
/* Copy all lines into a local cache so we can reuse them later on more easily. */
|
||||||
ParagraphLayout::Line *l;
|
const ParagraphLayouter::Line *l;
|
||||||
while ((l = line.layout->nextLine(maxw)) != NULL) {
|
while ((l = line.layout->NextLine(maxw)) != NULL) {
|
||||||
*this->Append() = l;
|
*this->Append() = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,9 +675,9 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi
|
||||||
Dimension Layouter::GetBounds()
|
Dimension Layouter::GetBounds()
|
||||||
{
|
{
|
||||||
Dimension d = { 0, 0 };
|
Dimension d = { 0, 0 };
|
||||||
for (ParagraphLayout::Line **l = this->Begin(); l != this->End(); l++) {
|
for (const ParagraphLayouter::Line **l = this->Begin(); l != this->End(); l++) {
|
||||||
d.width = max<uint>(d.width, (*l)->getWidth());
|
d.width = max<uint>(d.width, (*l)->GetWidth());
|
||||||
d.height += (*l)->getLeading();
|
d.height += (*l)->GetLeading();
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
@ -557,22 +709,22 @@ Point Layouter::GetCharPosition(const char *ch) const
|
||||||
|
|
||||||
if (str == ch) {
|
if (str == ch) {
|
||||||
/* Valid character. */
|
/* 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. */
|
/* Pointer to the end-of-string/line marker? Return total line width. */
|
||||||
if (*ch == '\0' || *ch == '\n') {
|
if (*ch == '\0' || *ch == '\n') {
|
||||||
Point p = { line->getWidth(), 0 };
|
Point p = { line->GetWidth(), 0 };
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan all runs until we've found our code point index. */
|
/* Scan all runs until we've found our code point index. */
|
||||||
for (int run_index = 0; run_index < line->countRuns(); run_index++) {
|
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
|
||||||
const ParagraphLayout::VisualRun *run = line->getVisualRun(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. */
|
/* Matching glyph? Return position. */
|
||||||
if ((size_t)run->getGlyphToCharMap()[i] == index) {
|
if ((size_t)run->GetGlyphToCharMap()[i] == index) {
|
||||||
Point p = { (int)run->getPositions()[i * 2], (int)run->getPositions()[i * 2 + 1] };
|
Point p = { (int)run->GetPositions()[i * 2], (int)run->GetPositions()[i * 2 + 1] };
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,84 +97,47 @@ public:
|
||||||
/** Mapping from index to font. */
|
/** Mapping from index to font. */
|
||||||
typedef SmallMap<int, Font *> FontMap;
|
typedef SmallMap<int, Font *> FontMap;
|
||||||
|
|
||||||
#ifndef WITH_ICU
|
|
||||||
/**
|
/**
|
||||||
* Class handling the splitting of a paragraph of text into lines and
|
* Interface to glue fallback and normal layouter into one.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
class ParagraphLayout {
|
class ParagraphLayouter {
|
||||||
public:
|
public:
|
||||||
|
virtual ~ParagraphLayouter() {}
|
||||||
|
|
||||||
/** Visual run contains data about the bit of text with the same font. */
|
/** Visual run contains data about the bit of text with the same font. */
|
||||||
class VisualRun {
|
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:
|
public:
|
||||||
VisualRun(Font *font, const WChar *chars, int glyph_count, int x);
|
virtual ~VisualRun() {}
|
||||||
~VisualRun();
|
virtual const Font *GetFont() const = 0;
|
||||||
Font *getFont() const;
|
virtual int GetGlyphCount() const = 0;
|
||||||
int getGlyphCount() const;
|
virtual const GlyphID *GetGlyphs() const = 0;
|
||||||
const GlyphID *getGlyphs() const;
|
virtual const float *GetPositions() const = 0;
|
||||||
float *getPositions() const;
|
virtual int GetLeading() const = 0;
|
||||||
int getLeading() const;
|
virtual const int *GetGlyphToCharMap() const = 0;
|
||||||
const int *getGlyphToCharMap() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A single line worth of VisualRuns. */
|
/** A single line worth of VisualRuns. */
|
||||||
class Line : public AutoDeleteSmallVector<VisualRun *, 4> {
|
class Line {
|
||||||
public:
|
public:
|
||||||
int getLeading() const;
|
virtual ~Line() {}
|
||||||
int getWidth() const;
|
virtual int GetLeading() const = 0;
|
||||||
int countRuns() const;
|
virtual int GetWidth() const = 0;
|
||||||
VisualRun *getVisualRun(int run) const;
|
virtual int CountRuns() const = 0;
|
||||||
|
virtual const VisualRun *GetVisualRun(int run) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const WChar *buffer_begin; ///< Begin of the buffer.
|
virtual void Reflow() = 0;
|
||||||
const WChar *buffer; ///< The current location in the buffer.
|
virtual const Line *NextLine(int max_width) = 0;
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
#endif /* !WITH_ICU */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The layouter performs all the layout work.
|
* The layouter performs all the layout work.
|
||||||
*
|
*
|
||||||
* It also accounts for the memory allocations and frees.
|
* It also accounts for the memory allocations and frees.
|
||||||
*/
|
*/
|
||||||
class Layouter : public AutoDeleteSmallVector<ParagraphLayout::Line *, 4> {
|
class Layouter : public AutoDeleteSmallVector<const ParagraphLayouter::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 */
|
|
||||||
|
|
||||||
const char *string; ///< Pointer to the original string.
|
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 */
|
/** Key into the linecache */
|
||||||
struct LineCacheKey {
|
struct LineCacheKey {
|
||||||
FontState state_before; ///< Font state at the beginning of the line.
|
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;
|
return this->str < other.str;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
public:
|
||||||
/** Item in the linecache */
|
/** Item in the linecache */
|
||||||
struct LineCacheItem {
|
struct LineCacheItem {
|
||||||
/* Stuff that cannot be freed until the ParagraphLayout is freed */
|
/* Stuff that cannot be freed until the ParagraphLayout is freed */
|
||||||
CharType buffer[DRAW_STRING_BUFFER]; ///< Accessed by both ICU's and our ParagraphLayout::nextLine.
|
void *buffer; ///< Accessed by both ICU's and our ParagraphLayout::nextLine.
|
||||||
FontMap runs; ///< Accessed by our ParagraphLayout::nextLine.
|
FontMap runs; ///< Accessed by our ParagraphLayout::nextLine.
|
||||||
|
|
||||||
FontState state_after; ///< Font state after the line.
|
FontState state_after; ///< Font state after the line.
|
||||||
ParagraphLayout *layout; ///< Layout of the line.
|
ParagraphLayouter *layout; ///< Layout of the line.
|
||||||
|
|
||||||
LineCacheItem() : layout(NULL) {}
|
LineCacheItem() : buffer(NULL), layout(NULL) {}
|
||||||
~LineCacheItem() { delete layout; }
|
~LineCacheItem() { delete layout; free(buffer); }
|
||||||
};
|
};
|
||||||
|
private:
|
||||||
typedef std::map<LineCacheKey, LineCacheItem> LineCache;
|
typedef std::map<LineCacheKey, LineCacheItem> LineCache;
|
||||||
static LineCache *linecache;
|
static LineCache *linecache;
|
||||||
|
|
||||||
|
@ -208,9 +173,9 @@ class Layouter : public AutoDeleteSmallVector<ParagraphLayout::Line *, 4> {
|
||||||
|
|
||||||
typedef SmallMap<TextColour, Font *> FontColourMap;
|
typedef SmallMap<TextColour, Font *> FontColourMap;
|
||||||
static FontColourMap fonts[FS_END];
|
static FontColourMap fonts[FS_END];
|
||||||
|
public:
|
||||||
static Font *GetFont(FontSize size, TextColour colour);
|
static Font *GetFont(FontSize size, TextColour colour);
|
||||||
|
|
||||||
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);
|
||||||
Dimension GetBounds();
|
Dimension GetBounds();
|
||||||
Point GetCharPosition(const char *ch) const;
|
Point GetCharPosition(const char *ch) const;
|
||||||
|
|
|
@ -127,7 +127,8 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Import a library.
|
* 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 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.
|
* @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.
|
* @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
|
* Scripts must or can implemented to provide information to OpenTTD to
|
||||||
* base configuring/starting/loading the Script on.
|
* base configuring/starting/loading the Script on.
|
||||||
*
|
*
|
||||||
* @note The required functions are also needed for Script Libraries. As such
|
* @note The required functions are also needed for Script Libraries, but in
|
||||||
* the information here can be used for libraries, but the information
|
* that case you extend ScriptLibrary. As such the information here can
|
||||||
* will not be shown in the GUI except for error/debug messages.
|
* be used for libraries, but the information will not be shown in the
|
||||||
|
* GUI except for error/debug messages.
|
||||||
*
|
*
|
||||||
* @api ai game
|
* @api ai game
|
||||||
*/
|
*/
|
||||||
|
@ -43,6 +44,8 @@ public:
|
||||||
*
|
*
|
||||||
* @return The name of the Script.
|
* @return The name of the Script.
|
||||||
* @note This function is required.
|
* @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();
|
string GetName();
|
||||||
|
|
||||||
|
@ -144,7 +147,8 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name of main class of the Script so OpenTTD knows
|
* 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.
|
* @return The class name of the Script.
|
||||||
* @note This function is required.
|
* @note This function is required.
|
||||||
|
|
|
@ -3131,12 +3131,14 @@ static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, i
|
||||||
if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
|
if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
|
||||||
stop &= TILE_SIZE - 1;
|
stop &= TILE_SIZE - 1;
|
||||||
|
|
||||||
if (x >= stop) return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
|
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;
|
v->vehstatus |= VS_TRAIN_SLOWING;
|
||||||
uint16 spd = max(0, (stop - x) * 20 - 15);
|
uint16 spd = max(0, (stop - x) * 20 - 15);
|
||||||
if (spd < v->cur_speed) v->cur_speed = spd;
|
if (spd < v->cur_speed) v->cur_speed = spd;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (v->type == VEH_ROAD) {
|
} else if (v->type == VEH_ROAD) {
|
||||||
RoadVehicle *rv = RoadVehicle::From(v);
|
RoadVehicle *rv = RoadVehicle::From(v);
|
||||||
if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) {
|
if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) {
|
||||||
|
|
Loading…
Reference in New Issue