~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to ext/native/util/text/wrap_text.cpp

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <cstring>
 
2
#include "util/text/utf8.h"
 
3
#include "util/text/wrap_text.h"
 
4
 
 
5
bool WordWrapper::IsCJK(uint32_t c) {
 
6
        if (c < 0x1000) {
 
7
                return false;
 
8
        }
 
9
 
 
10
        // CJK characters can be wrapped more freely.
 
11
        bool result = (c >= 0x1100 && c <= 0x11FF); // Hangul Jamo.
 
12
        result = result || (c >= 0x2E80 && c <= 0x2FFF); // Kangxi Radicals etc.
 
13
#if 0
 
14
        result = result || (c >= 0x3040 && c <= 0x31FF); // Hiragana, Katakana, Hangul Compatibility Jamo etc.
 
15
        result = result || (c >= 0x3200 && c <= 0x32FF); // CJK Enclosed
 
16
        result = result || (c >= 0x3300 && c <= 0x33FF); // CJK Compatibility
 
17
        result = result || (c >= 0x3400 && c <= 0x4DB5); // CJK Unified Ideographs Extension A
 
18
#else
 
19
        result = result || (c >= 0x3040 && c <= 0x4DB5); // Above collapsed
 
20
#endif
 
21
        result = result || (c >= 0x4E00 && c <= 0x9FBB); // CJK Unified Ideographs
 
22
        result = result || (c >= 0xAC00 && c <= 0xD7AF); // Hangul Syllables
 
23
        result = result || (c >= 0xF900 && c <= 0xFAD9); // CJK Compatibility Ideographs
 
24
        result = result || (c >= 0x20000 && c <= 0x2A6D6); // CJK Unified Ideographs Extension B
 
25
        result = result || (c >= 0x2F800 && c <= 0x2FA1D); // CJK Compatibility Supplement
 
26
        return result;
 
27
}
 
28
 
 
29
bool WordWrapper::IsPunctuation(uint32_t c) {
 
30
        switch (c) {
 
31
        // TODO: This list of punctuation is very incomplete.
 
32
        case ',':
 
33
        case '.':
 
34
        case ':':
 
35
        case '!':
 
36
        case ')':
 
37
        case '?':
 
38
        case 0x00AD: // SOFT HYPHEN
 
39
        case 0x3001: // IDEOGRAPHIC COMMA
 
40
        case 0x3002: // IDEOGRAPHIC FULL STOP
 
41
        case 0x06D4: // ARABIC FULL STOP
 
42
        case 0xFF01: // FULLWIDTH EXCLAMATION MARK
 
43
        case 0xFF09: // FULLWIDTH RIGHT PARENTHESIS
 
44
        case 0xFF1F: // FULLWIDTH QUESTION MARK
 
45
                return true;
 
46
 
 
47
        default:
 
48
                return false;
 
49
        }
 
50
}
 
51
 
 
52
bool WordWrapper::IsSpace(uint32_t c) {
 
53
        switch (c) {
 
54
        case '\t':
 
55
        case ' ':
 
56
        case 0x2002: // EN SPACE
 
57
        case 0x2003: // EM SPACE
 
58
        case 0x3000: // IDEOGRAPHIC SPACE
 
59
                return true;
 
60
 
 
61
        default:
 
62
                return false;
 
63
        }
 
64
}
 
65
 
 
66
bool WordWrapper::IsShy(uint32_t c) {
 
67
        return c == 0x00AD; // SOFT HYPHEN
 
68
}
 
69
 
 
70
std::string WordWrapper::Wrapped() {
 
71
        if (out_.empty()) {
 
72
                Wrap();
 
73
        }
 
74
        return out_;
 
75
}
 
76
 
 
77
void WordWrapper::WrapBeforeWord() {
 
78
        if (x_ + wordWidth_ > maxW_) {
 
79
                if (IsShy(out_[out_.size() - 1])) {
 
80
                        // Soft hyphen, replace it with a real hyphen since we wrapped at it.
 
81
                        // TODO: There's an edge case here where the hyphen might not fit.
 
82
                        out_[out_.size() - 1] = '-';
 
83
                }
 
84
                out_ += "\n";
 
85
                x_ = 0.0f;
 
86
                forceEarlyWrap_ = false;
 
87
        }
 
88
}
 
89
 
 
90
void WordWrapper::AppendWord(int endIndex, bool addNewline) {
 
91
        WrapBeforeWord();
 
92
        // This will include the newline.
 
93
        out_ += std::string(str_ + lastIndex_, endIndex - lastIndex_);
 
94
        if (addNewline) {
 
95
                out_ += "\n";
 
96
        }
 
97
        lastIndex_ = endIndex;
 
98
}
 
99
 
 
100
void WordWrapper::Wrap() {
 
101
        out_.clear();
 
102
 
 
103
        // First, let's check if it fits as-is.
 
104
        size_t len = strlen(str_);
 
105
        if (MeasureWidth(str_, len) <= maxW_) {
 
106
                // If it fits, we don't need to go through each character.
 
107
                out_ = str_;
 
108
                return;
 
109
        }
 
110
 
 
111
        for (UTF8 utf(str_); !utf.end(); ) {
 
112
                int beforeIndex = utf.byteIndex();
 
113
                uint32_t c = utf.next();
 
114
                int afterIndex = utf.byteIndex();
 
115
 
 
116
                // Is this a newline character, hard wrapping?
 
117
                if (c == '\n') {
 
118
                        // This will include the newline character.
 
119
                        AppendWord(afterIndex, false);
 
120
                        x_ = 0.0f;
 
121
                        wordWidth_ = 0.0f;
 
122
                        // We wrapped once, so stop forcing.
 
123
                        forceEarlyWrap_ = false;
 
124
                        continue;
 
125
                }
 
126
 
 
127
                float newWordWidth = 0.0f;
 
128
                if (c == '\n') {
 
129
                        newWordWidth = wordWidth_;
 
130
                } else {
 
131
                        // Measure the entire word for kerning purposes.  May not be 100% perfect.
 
132
                        newWordWidth = MeasureWidth(str_ + lastIndex_, afterIndex - lastIndex_);
 
133
                }
 
134
 
 
135
                // Is this the end of a word (space)?
 
136
                if (wordWidth_ > 0.0f && IsSpace(c)) {
 
137
                        AppendWord(afterIndex, false);
 
138
                        // We include the space in the x increase.
 
139
                        // If the space takes it over, we'll wrap on the next word.
 
140
                        x_ += newWordWidth;
 
141
                        wordWidth_ = 0.0f;
 
142
                        continue;
 
143
                }
 
144
 
 
145
                // Can the word fit on a line even all by itself so far?
 
146
                if (wordWidth_ > 0.0f && newWordWidth > maxW_) {
 
147
                        // Nope.  Let's drop what's there so far onto its own line.
 
148
                        if (x_ > 0.0f && x_ + wordWidth_ > maxW_ && beforeIndex > lastIndex_) {
 
149
                                // Let's put as many characters as will fit on the previous line.
 
150
                                // This word can't fit on one line even, so it's going to be cut into pieces anyway.
 
151
                                // Better to avoid huge gaps, in that case.
 
152
                                forceEarlyWrap_ = true;
 
153
 
 
154
                                // Now rewind back to where the word started so we can wrap at the opportune moment.
 
155
                                wordWidth_ = 0.0f;
 
156
                                while (utf.byteIndex() > lastIndex_) {
 
157
                                        utf.bwd();
 
158
                                }
 
159
                                continue;
 
160
                        }
 
161
                        // Now, add the word so far (without this latest character) and break.
 
162
                        AppendWord(beforeIndex, true);
 
163
                        x_ = 0.0f;
 
164
                        wordWidth_ = 0.0f;
 
165
                        forceEarlyWrap_ = false;
 
166
                        // The current character will be handled as part of the next word.
 
167
                        continue;
 
168
                }
 
169
 
 
170
                wordWidth_ = newWordWidth;
 
171
 
 
172
                // Is this the end of a word via punctuation / CJK?
 
173
                if (wordWidth_ > 0.0f && (IsCJK(c) || IsPunctuation(c) || forceEarlyWrap_)) {
 
174
                        // CJK doesn't require spaces, so we treat each letter as its own word.
 
175
                        AppendWord(afterIndex, false);
 
176
                        x_ += wordWidth_;
 
177
                        wordWidth_ = 0.0f;
 
178
                }
 
179
        }
 
180
 
 
181
        // Now insert the rest of the string - the last word.
 
182
        AppendWord((int)len, false);
 
183
}