00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "gfx_layout.h"
00014 #include "string_func.h"
00015 #include "strings_func.h"
00016
00017 #include "table/control_codes.h"
00018
00019 #ifdef WITH_ICU
00020 #include <unicode/ustring.h>
00021 #endif
00022
00028 Font::Font(FontSize size, TextColour colour) :
00029 fc(FontCache::Get(size)), colour(colour)
00030 {
00031 assert(size < FS_END);
00032 }
00033
00034 #ifdef WITH_ICU
00035
00036
00037 le_int32 Font::getUnitsPerEM() const
00038 {
00039 return this->fc->GetUnitsPerEM();
00040 }
00041
00042 le_int32 Font::getAscent() const
00043 {
00044 return this->fc->GetAscender();
00045 }
00046
00047 le_int32 Font::getDescent() const
00048 {
00049 return -this->fc->GetDescender();
00050 }
00051
00052 le_int32 Font::getLeading() const
00053 {
00054 return this->fc->GetHeight();
00055 }
00056
00057 float Font::getXPixelsPerEm() const
00058 {
00059 return (float)this->fc->GetHeight();
00060 }
00061
00062 float Font::getYPixelsPerEm() const
00063 {
00064 return (float)this->fc->GetHeight();
00065 }
00066
00067 float Font::getScaleFactorX() const
00068 {
00069 return 1.0f;
00070 }
00071
00072 float Font::getScaleFactorY() const
00073 {
00074 return 1.0f;
00075 }
00076
00077 const void *Font::getFontTable(LETag tableTag) const
00078 {
00079 size_t length;
00080 return this->getFontTable(tableTag, length);
00081 }
00082
00083 const void *Font::getFontTable(LETag tableTag, size_t &length) const
00084 {
00085 return this->fc->GetFontTable(tableTag, length);
00086 }
00087
00088 LEGlyphID Font::mapCharToGlyph(LEUnicode32 ch) const
00089 {
00090 if (IsTextDirectionChar(ch)) return 0;
00091 return this->fc->MapCharToGlyph(ch);
00092 }
00093
00094 void Font::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const
00095 {
00096 advance.fX = glyph == 0xFFFF ? 0 : this->fc->GetGlyphWidth(glyph);
00097 advance.fY = 0;
00098 }
00099
00100 le_bool Font::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const
00101 {
00102 return FALSE;
00103 }
00104
00105 size_t Layouter::AppendToBuffer(UChar *buff, const UChar *buffer_last, WChar c)
00106 {
00107
00108 int32 length = 0;
00109 UErrorCode err = U_ZERO_ERROR;
00110 u_strFromUTF32(buff, buffer_last - buff, &length, (UChar32*)&c, 1, &err);
00111 return length;
00112 }
00113
00114 ParagraphLayout *Layouter::GetParagraphLayout(UChar *buff, UChar *buff_end, FontMap &fontMapping)
00115 {
00116 int32 length = buff_end - buff;
00117
00118 if (length == 0) {
00119
00120 buff[0] = ' ';
00121 length = 1;
00122 fontMapping.End()[-1].first++;
00123 }
00124
00125
00126 FontRuns runs(fontMapping.Length());
00127 for (FontMap::iterator iter = fontMapping.Begin(); iter != fontMapping.End(); iter++) {
00128 runs.add(iter->second, iter->first);
00129 }
00130
00131 LEErrorCode status = LE_NO_ERROR;
00132 return new ParagraphLayout(buff, length, &runs, NULL, NULL, NULL, _current_text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, false, status);
00133 }
00134
00135 #else
00136
00137
00138
00146 ParagraphLayout::VisualRun::VisualRun(Font *font, const WChar *chars, int char_count, int x) :
00147 font(font), glyph_count(char_count)
00148 {
00149 this->glyphs = MallocT<GlyphID>(this->glyph_count);
00150
00151
00152 this->positions = MallocT<float>(this->glyph_count * 2 + 2);
00153 this->positions[0] = x;
00154 this->positions[1] = 0;
00155
00156 for (int i = 0; i < this->glyph_count; i++) {
00157 this->glyphs[i] = font->fc->MapCharToGlyph(chars[i]);
00158 this->positions[2 * i + 2] = this->positions[2 * i] + font->fc->GetGlyphWidth(this->glyphs[i]);
00159 this->positions[2 * i + 3] = 0;
00160 }
00161 }
00162
00164 ParagraphLayout::VisualRun::~VisualRun()
00165 {
00166 free(this->positions);
00167 free(this->glyphs);
00168 }
00169
00174 Font *ParagraphLayout::VisualRun::getFont() const
00175 {
00176 return this->font;
00177 }
00178
00183 int ParagraphLayout::VisualRun::getGlyphCount() const
00184 {
00185 return this->glyph_count;
00186 }
00187
00192 const GlyphID *ParagraphLayout::VisualRun::getGlyphs() const
00193 {
00194 return this->glyphs;
00195 }
00196
00201 float *ParagraphLayout::VisualRun::getPositions() const
00202 {
00203 return this->positions;
00204 }
00205
00210 int ParagraphLayout::VisualRun::getLeading() const
00211 {
00212 return this->getFont()->fc->GetHeight();
00213 }
00214
00219 int ParagraphLayout::Line::getLeading() const
00220 {
00221 int leading = 0;
00222 for (const VisualRun * const *run = this->Begin(); run != this->End(); run++) {
00223 leading = max(leading, (*run)->getLeading());
00224 }
00225
00226 return leading;
00227 }
00228
00233 int ParagraphLayout::Line::getWidth() const
00234 {
00235 if (this->Length() == 0) return 0;
00236
00237
00238
00239
00240
00241
00242 const VisualRun *run = this->getVisualRun(this->countRuns() - 1);
00243 return run->getPositions()[run->getGlyphCount() * 2];
00244 }
00245
00250 int ParagraphLayout::Line::countRuns() const
00251 {
00252 return this->Length();
00253 }
00254
00259 ParagraphLayout::VisualRun *ParagraphLayout::Line::getVisualRun(int run) const
00260 {
00261 return *this->Get(run);
00262 }
00263
00270 ParagraphLayout::ParagraphLayout(WChar *buffer, int length, FontMap &runs) : buffer_begin(buffer), buffer(buffer), runs(runs)
00271 {
00272 assert(runs.End()[-1].first == length);
00273 }
00274
00280 ParagraphLayout::Line *ParagraphLayout::nextLine(int max_width)
00281 {
00282
00283
00284
00285
00286 if (this->buffer == NULL) return NULL;
00287
00288 Line *l = new Line();
00289
00290 if (*this->buffer == '\0') {
00291
00292 this->buffer = NULL;
00293 *l->Append() = new VisualRun(this->runs.Begin()->second, this->buffer, 0, 0);
00294 return l;
00295 }
00296
00297 const WChar *begin = this->buffer;
00298 WChar *last_space = NULL;
00299 const WChar *last_char = begin;
00300 int width = 0;
00301
00302 int offset = this->buffer - this->buffer_begin;
00303 FontMap::iterator iter = this->runs.Begin();
00304 while (iter->first <= offset) {
00305 iter++;
00306 assert(iter != this->runs.End());
00307 }
00308
00309 const FontCache *fc = iter->second->fc;
00310 const WChar *next_run = this->buffer_begin + iter->first;
00311
00312 for (;;) {
00313 WChar c = *this->buffer;
00314 last_char = this->buffer;
00315
00316 if (c == '\0') {
00317 this->buffer = NULL;
00318 break;
00319 }
00320
00321 if (this->buffer == next_run) {
00322 *l->Append() = new VisualRun(iter->second, begin, this->buffer - begin, l->getWidth());
00323 iter++;
00324 assert(iter != this->runs.End());
00325
00326 next_run = this->buffer_begin + iter->first;
00327 begin = this->buffer;
00328
00329 last_space = NULL;
00330 }
00331
00332 if (IsWhitespace(c)) last_space = this->buffer;
00333
00334 if (IsPrintable(c) && !IsTextDirectionChar(c)) {
00335 int char_width = GetCharacterWidth(fc->GetSize(), c);
00336 width += char_width;
00337 if (width > max_width) {
00338
00339
00340 if (width == char_width) {
00341
00342
00343 this->buffer = NULL;
00344 return l;
00345 }
00346
00347 if (last_space == NULL) {
00348
00349
00350
00351
00352
00353
00354 last_char = this->buffer;
00355 } else {
00356
00357 this->buffer = last_space;
00358 last_char = last_space;
00359 }
00360 break;
00361 }
00362 }
00363
00364 this->buffer++;
00365 }
00366
00367 if (l->Length() == 0 || last_char - begin != 0) {
00368 *l->Append() = new VisualRun(iter->second, begin, last_char - begin, l->getWidth());
00369 }
00370 return l;
00371 }
00372
00380 size_t Layouter::AppendToBuffer(WChar *buff, const WChar *buffer_last, WChar c)
00381 {
00382 *buff = c;
00383 return 1;
00384 }
00385
00393 ParagraphLayout *Layouter::GetParagraphLayout(WChar *buff, WChar *buff_end, FontMap &fontMapping)
00394 {
00395 return new ParagraphLayout(buff, buff_end - buff, fontMapping);
00396 }
00397 #endif
00398
00406 Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsize)
00407 {
00408 const CharType *buffer_last = lastof(this->buffer);
00409 CharType *buff = this->buffer;
00410
00411 TextColour cur_colour = colour, prev_colour = colour;
00412 WChar c = 0;
00413
00414 do {
00415 Font *f = new Font(fontsize, cur_colour);
00416 CharType *buff_begin = buff;
00417 FontMap fontMapping;
00418
00419
00420
00421
00422
00423
00424 for (; buff < buffer_last;) {
00425 c = Utf8Consume(const_cast<const char **>(&str));
00426 if (c == '\0' || c == '\n') {
00427 break;
00428 } else if (c >= SCC_BLUE && c <= SCC_BLACK) {
00429 prev_colour = cur_colour;
00430 cur_colour = (TextColour)(c - SCC_BLUE);
00431 } else if (c == SCC_PREVIOUS_COLOUR) {
00432 Swap(prev_colour, cur_colour);
00433 } else if (c == SCC_TINYFONT) {
00434 fontsize = FS_SMALL;
00435 } else if (c == SCC_BIGFONT) {
00436 fontsize = FS_LARGE;
00437 } else {
00438 buff += AppendToBuffer(buff, buffer_last, c);
00439 continue;
00440 }
00441
00442 if (!fontMapping.Contains(buff - buff_begin)) {
00443 fontMapping.Insert(buff - buff_begin, f);
00444 *this->fonts.Append() = f;
00445 } else {
00446 delete f;
00447 }
00448 f = new Font(fontsize, cur_colour);
00449 }
00450
00451
00452 *buff = '\0';
00453
00454 if (!fontMapping.Contains(buff - buff_begin)) {
00455 fontMapping.Insert(buff - buff_begin, f);
00456 *this->fonts.Append() = f;
00457 }
00458 ParagraphLayout *p = GetParagraphLayout(buff_begin, buff, fontMapping);
00459
00460
00461 ParagraphLayout::Line *l;
00462 while ((l = p->nextLine(maxw)) != NULL) {
00463 *this->Append() = l;
00464 }
00465
00466 delete p;
00467
00468 } while (c != '\0' && buff < buffer_last);
00469 }
00470
00472 Layouter::~Layouter()
00473 {
00474 for (Font **iter = this->fonts.Begin(); iter != this->fonts.End(); iter++) {
00475 delete *iter;
00476 }
00477 }
00478
00483 Dimension Layouter::GetBounds()
00484 {
00485 Dimension d = { 0, 0 };
00486 for (ParagraphLayout::Line **l = this->Begin(); l != this->End(); l++) {
00487 d.width = max<uint>(d.width, (*l)->getWidth());
00488 d.height += (*l)->getLeading();
00489 }
00490 return d;
00491 }