66
66
const unsigned int MAX_PAGE_HISTORY = 100;
68
const int FULLWIDTH_NUMBER_SIGN = 0xFF03;
69
const int FULLWIDTH_A = 0xFF21;
70
const int FULLWIDTH_B = 0xFF22;
71
const int FULLWIDTH_ZERO = 0xFF10;
72
const int FULLWIDTH_NINE = 0xFF19;
68
74
// -----------------------------------------------------------------------
69
75
// TextSystemGlobals
70
76
// -----------------------------------------------------------------------
495
502
boost::shared_ptr<Surface> TextSystem::renderText(
496
503
const std::string& utf8str, int size, int xspace, int yspace,
497
const RGBColour& colour, RGBColour* shadow_colour) {
504
const RGBColour& colour, RGBColour* shadow_colour,
505
int max_chars_in_line) {
506
const int line_max_width =
507
(max_chars_in_line > 0) ? (size + xspace) * max_chars_in_line :
498
510
// On the first pass, we figure out how large of a surface we need for
499
511
// rendering the text.
500
512
int current_size = size;
502
514
int max_width = 0;
503
515
int current_line_width = 0;
504
516
int current_line_height = 0;
517
bool should_break = false;
505
518
std::string::const_iterator it = utf8str.begin();
506
519
std::string::const_iterator strend = utf8str.end();
507
520
while (it != strend) {
508
521
int codepoint = utf8::next(it, strend);
509
522
bool add_char = true;
523
bool is_emoji = false;
511
525
if (codepoint == '#') {
512
526
add_char = false;
513
527
codepoint = utf8::next(it, strend);
514
528
switch (codepoint) {
515
// TODO(erg): While playtesting with this new parser, I noticed a '#a'
516
// control code that wasn't mentioned in xclannad's source or in rldev,
517
// but is used in Little Busters.
520
total_height += current_line_height + yspace;
521
current_line_height = 0;
561
} else if (codepoint == FULLWIDTH_NUMBER_SIGN) {
562
// The codepoint is a fullwidth '#'. If the codepoint after this is a
563
// fullwidth 'A' or 'B', followed by two fullwidth digits, we have an
564
// emoji code, and should treat it like a fullwidth space during the
566
std::string::const_iterator n = it;
567
int next_codepoint = utf8::next(n, strend);
568
if (next_codepoint == FULLWIDTH_A || next_codepoint == FULLWIDTH_B) {
569
int num_one = utf8::next(n, strend);
570
int num_two = utf8::next(n, strend);
571
if (num_one >= FULLWIDTH_ZERO && num_one <= FULLWIDTH_NINE &&
572
num_two >= FULLWIDTH_ZERO && num_two <= FULLWIDTH_NINE) {
573
// This is an emoji mark. We should consume all input so far.
554
int w = charWidth(current_size, codepoint);
555
// TODO(erg): xspace should be added on the next character add.
556
current_line_width += (w + xspace);
582
added_width = charWidth(current_size, codepoint) + xspace;
584
added_width = size + xspace;
587
if (should_break || current_line_width + added_width > line_max_width) {
588
total_height += current_line_height + yspace;
589
current_line_height = current_size;
590
current_line_width = added_width;
591
should_break = false;
593
current_line_width += added_width;
594
current_line_height = std::max(current_line_height, current_size);
558
597
max_width = std::max(max_width, current_line_width);
559
current_line_height = std::max(current_line_height, current_size);
562
600
total_height += current_line_height;
601
should_break = false;
603
// If this text has a shadow, our surface needs to have a final two pixels
604
// added to the bottom and right to accommodate it.
564
610
// TODO(erg): Surely there's a way to allocate with something other than
672
} else if (codepoint == FULLWIDTH_NUMBER_SIGN) {
673
// The codepoint is a fullwidth '#'. If the codepoint after this is a
674
// fullwidth 'A' or 'B', followed by two fullwidth digits, we have an
675
// emoji code, and should treat it like a fullwidth space during the
677
std::string::const_iterator n = cur_end;
678
int next_codepoint = utf8::next(n, strend);
679
if (next_codepoint == FULLWIDTH_A || next_codepoint == FULLWIDTH_B) {
680
int num_one = utf8::next(n, strend);
681
int num_two = utf8::next(n, strend);
682
if (num_one >= FULLWIDTH_ZERO && num_one <= FULLWIDTH_NINE &&
683
num_two >= FULLWIDTH_ZERO && num_two <= FULLWIDTH_NINE) {
684
// This is an emoji mark. We should consume all input so far.
687
// Get the emoji number from the text.
688
num_one -= FULLWIDTH_ZERO;
689
num_two -= FULLWIDTH_ZERO;
690
emoji_id = num_one * 10 + num_two;
692
// Lookup what g00 surface we should use for emoji.
693
emoji_surface = system().graphics().GetEmojiSurface();
702
// If we add this character, will we horizontally overflow?
703
item_width = charWidth(current_size, codepoint);
704
} else if (is_emoji) {
705
// Whatever the real size is, we only allocate the incoming size. This
706
// means that if the emoji is larger than |size|, we'll draw text over
707
// it. This is to be bug for bug compatible with RealLive.
712
if (should_break || currentX + item_width > max_width) {
714
currentY += current_line_height + yspace;
715
current_line_height = 0;
716
should_break = false;
635
728
currentX += s.width() + xspace;
636
729
current_line_height = std::max(current_line_height, current_size);
730
} else if (is_emoji) {
732
// Emoji surfaces don't have internal pattnos. Instead, assume that
733
// icons are square and laid out to the right, sort of like mouse
735
int height = emoji_surface->size().height();
736
Rect src = Rect(height * emoji_id, 0, Size(height, height));
737
Rect dst = Rect(currentX, currentY, Size(height, height));
738
emoji_surface->blitToSurface(*surface, src, dst, 255, false);
741
currentX += size + xspace;
742
current_line_height = std::max(current_line_height, current_size);
645
751
void TextSystem::reset() {
646
752
is_reading_backlog_ = false;
753
script_message_no_wait_ = false;
648
755
current_pageset_ = std::auto_ptr<PageSet>(new PageSet);
649
756
previous_page_sets_.clear();