Mercurial > otakunoraifu
annotate font/font_layout.cc @ 66:d112357a0ec1
Fix a bug with savegames introduced with changeset c7bcc0ec2267.
Warning: savegames created since c7bcc0ec2267 are probably corrupted,
you may have to start the game over.
If you chose not to do so, you should replace all occurrences of 'TextWindow' by 'TextImplWindow',
and 'Text Window' by 'TextImpl Window' in your save files.
author | Thibaut Girka <thib@sitedethib.com> |
---|---|
date | Sat, 11 Dec 2010 18:36:20 +0100 |
parents | 4416cfac86ae |
children |
rev | line source |
---|---|
0 | 1 /* layout2.cc |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
2 * テキストの禁則処理、レイアウトなどを行う |
0 | 3 */ |
4 /* | |
5 * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno | |
6 * All rights reserved. | |
7 * | |
8 * Redistribution and use in source and binary forms, with or without | |
9 * modification, are permitted provided that the following conditions | |
10 * are met: | |
11 * 1. Redistributions of source code must retain the above copyright | |
12 * notice, this list of conditions and the following disclaimer. | |
13 * 2. Redistributions in binary form must reproduce the above copyright | |
14 * notice, this list of conditions and the following disclaimer in the | |
15 * documentation and/or other materials provided with the distribution. | |
16 * 3. The name of the author may not be used to endorse or promote products | |
17 * derived from this software without specific prior written permission. | |
18 * | |
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
52 | 31 #include <vector> |
32 #include <map> | |
33 #include <iostream> | |
0 | 34 |
35 using namespace std; | |
36 | |
52 | 37 #include "font.h" |
38 #include "text.h" | |
0 | 39 |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
40 const int line_skip = 1; // 行と行の間の間隔 |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
41 const int ruby_textskip = 0; // 文字とルビの間の間隔 |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
42 const int ruby_lineskip = 1; // ルビがあるときに行間に加える値 |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
43 const double ruby_scale = 0.4; // ルビのスケール |
0 | 44 |
45 class TextGlyphStreamHelper; | |
46 | |
47 enum KinsokuType { KinsokuHead = 1, KinsokuTail = 2}; | |
48 static int kinsoku_table1[] = { | |
49 /* 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 */ | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
50 0,0,2,2,2,2,0,0, /* X 、。,.・: */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
51 0,2,2,0,0,0,0,0, /* ;?!゛゜´`¨ */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
52 0,0,0,0,0,0,0,0, /* ^ ̄_ヽヾゝゞ〃 */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
53 0,0,0,0,2,0,0,0, /* 仝々〆〇ー―‐/ */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
54 0,2,0,0,2,2,1,2, /* \〜‖|…‥‘’ */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
55 1,2,1,2,1,2,1,2, /* “”()〔〕[] */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
56 1,2,1,2,1,2,1,2, /* {}〈〉《》「」 */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
57 1,2,1,2,0,0,0,0, /* 『』【】+−±× */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
58 0,0,0,0,0,0,0,0, /* ÷=≠<>≦≧∞ */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
59 0,0,0,0,0,0,0,0, /* ∴♂♀°′″℃¥ */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
60 0,0,0,0,0,0,0,0, /* $¢£%#&*@ */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
61 0,0,0,0,0,0,0,0, /* §☆★○●◎◇X */ |
0 | 62 0 |
63 }; | |
64 static int kinsoku_table2[] = { | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
65 0,2,0,2,0,2,0,2,0,2,0,0,0,0,0,0, /* ぁあぃいぅうぇえぉおかがきぎく */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
66 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ぐけげこごさざしじすずせぜそぞた */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
67 0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, /* だちぢっつづてでとどなにぬねのは */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
68 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ばぱひびぴふぶぷへべぺほぼぽまみ */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
69 0,0,0,2,0,2,0,2,0,0,0,0,0,0,2,0, /* むめもゃやゅゆょよらりるれろゎわ */ |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
70 0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0, /* ゐゑをんヴヵヶ */ |
0 | 71 0 |
72 }; | |
73 | |
74 inline int Kinsoku(int code) { | |
75 if ( (code&0xff80) == 0xa180) return kinsoku_table1[ (code&0xff) - 0xa0]; | |
76 if ( (code&0xfe80) == 0xa480) return kinsoku_table2[ (code&0xff) - 0xa0]; /* code = 0xa400 / 0xa500 */ | |
77 return 0; | |
78 } | |
79 | |
80 class TextGlyphStreamHelper { | |
52 | 81 private: |
82 typedef TextStream::Iterator Iterator; | |
83 typedef TextGlyphStream::iterator iterator; | |
0 | 84 |
52 | 85 TextGlyphStream* data; |
0 | 86 |
52 | 87 // information for rendering |
88 unsigned char r, g, b; | |
89 XKFont::Face* face; | |
90 XKFont::Face* ruby_face; | |
91 XKFont::Font* font; | |
0 | 92 |
52 | 93 public: |
94 int min_lineheight; | |
95 TextGlyphStreamHelper(XKFont::Font* font); | |
96 // helper functions | |
97 void Init(TextGlyphStream* data); | |
98 Iterator Add(int& x, Iterator begin, Iterator end, int max_x = 0); | |
99 Iterator AddRuby(int& x, Iterator begin, Iterator end); | |
100 int CharWidth(int code); | |
101 void SetGroup(iterator begin, iterator end); | |
102 void CalcHeight(int& ascent, int& descent, iterator begin, iterator end); | |
103 void AdjustPosition(int xstart_add, int xend_add, int y_add, iterator begin, iterator end); | |
0 | 104 }; |
105 | |
106 TextGlyphStreamHelper::TextGlyphStreamHelper(XKFont::Font* __font) { | |
107 font = __font; | |
108 face = font->FaceLoad(1.0); | |
109 ruby_face = 0; | |
110 r = 255; g = 255; b = 255; | |
111 min_lineheight = font->vsize; | |
112 } | |
113 | |
114 void TextGlyphStreamHelper::Init(TextGlyphStream* __data) { | |
115 r = 255; g = 255; b = 255; | |
116 face = font->FaceLoad(1.0); | |
117 data = __data; | |
118 data->clear(); | |
119 data->font = font; | |
120 } | |
121 | |
122 TextGlyphStreamHelper::Iterator | |
123 TextGlyphStreamHelper::Add(int& x, TextGlyphStreamHelper::Iterator begin, TextGlyphStreamHelper::Iterator end, int max_x) { | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
124 /* text を glyph に変換する */ |
0 | 125 TextGlyph gl; |
126 Iterator it; | |
127 gl.x = x; gl.y = 0; gl.r = r; gl.g = g; gl.b = b; gl.flag = TextGlyph::Flag(0); gl.is_rev = false; | |
128 for (it = begin; it != end; it++) { | |
129 if (it->type != TextElem::glyph) { | |
130 if (it->type == TextElem::color) { | |
131 gl.r = r = it->impl.Color.r; | |
132 gl.g = g = it->impl.Color.g; | |
133 gl.b = b = it->impl.Color.b; | |
134 } else if (it->type == TextElem::size) { | |
50 | 135 delete face; |
0 | 136 face = font->FaceLoad(it->impl.Size.scale); |
137 } else if (it->type == TextElem::escape) { | |
138 x = gl.x; | |
139 return it; | |
140 } | |
141 continue; | |
142 } | |
143 try { | |
144 gl.glyph = face->GlyphLoad(it->impl.Glyph.code); | |
145 if (max_x > 0 && gl.x + gl.glyph->advance.x > max_x) { | |
146 x = gl.x; | |
147 return it; | |
148 } | |
149 if ( Kinsoku(it->impl.Glyph.code) == KinsokuTail) | |
150 gl.flag = TextGlyph::Flag(gl.flag | TextGlyph::Kinsoku); | |
151 else | |
152 gl.flag = TextGlyph::Flag(0); | |
153 data->push_back(gl); | |
154 gl.x += gl.glyph->advance.x; | |
155 } catch(...) {} | |
156 } | |
157 x = gl.x; | |
158 return it; | |
159 } | |
160 | |
161 TextGlyphStreamHelper::Iterator TextGlyphStreamHelper::AddRuby(int& x, TextGlyphStreamHelper::Iterator sbegin, TextGlyphStreamHelper::Iterator send) { | |
162 Iterator it; | |
163 it = sbegin; | |
164 if (it == send) return it; | |
165 if (it->type != TextElem::escape || it->impl.Escape.type != TextElem::ruby_start) return sbegin; | |
166 it++; | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
167 /* まず、本文描画 */ |
0 | 168 int str_firstpos = data->size(); |
169 int str_width = 0; | |
170 it = Add(str_width, it, send); | |
171 if (it == send || it->type != TextElem::escape || it->impl.Escape.type != TextElem::ruby_startruby) { | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
172 // ありえないはずだが、取り合えずなにもしないで終了 |
0 | 173 cerr << "TextGlyphStream::AddRuby : invalid operation; fallback to the upeer level"<<endl; |
174 data->erase(data->begin()+str_firstpos, data->end()); | |
175 return sbegin+1; | |
176 } | |
177 it++; | |
178 int str_lastpos = data->size()-1; | |
179 TextGlyph& str_first = data->begin()[str_firstpos]; | |
180 TextGlyph& str_last = data->back(); | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
181 // 次に、フォントを取りかえてルビ描画 |
0 | 182 int ruby_firstpos = data->size(); |
183 XKFont::Face* save_font = face; | |
184 if (ruby_face == 0) ruby_face = font->FaceLoad(ruby_scale); | |
185 face = ruby_face; | |
186 int ruby_width = 0; | |
187 it = Add(ruby_width, it, send); | |
188 if (it->type != TextElem::escape || it->impl.Escape.type != TextElem::ruby_end) { | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
189 /* ありえないはずだが、取り合えずなにもしないで終了 */ |
0 | 190 cerr << "TextGlyphStream::AddRuby : invalid operation; fallback to the upeer level"<<endl; |
191 data->erase(data->begin()+str_firstpos, data->end()); | |
192 return sbegin+1; | |
193 } | |
194 it++; | |
195 face = save_font; | |
196 TextGlyph& ruby_first = (*data)[ruby_firstpos]; | |
197 TextGlyph& ruby_last = data->back(); | |
198 | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
199 /* ルビを移動すべき高さを求める */ |
0 | 200 int dummy, str_ascent, ruby_descent; |
201 CalcHeight(str_ascent, dummy, data->begin()+str_firstpos, data->begin()+ruby_firstpos); | |
202 CalcHeight(dummy, ruby_descent, data->begin()+ruby_firstpos, data->end()); | |
203 int ruby_height = str_ascent + ruby_descent + ruby_textskip; | |
204 | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
205 /* センタリングした場合の、ルビの左側、右側のマージン */ |
0 | 206 int leftmergin, rightmergin; |
207 leftmergin = str_first.glyph->advance.x/2 - (ruby_first.glyph->advance.x+1)/2; | |
208 rightmergin = str_last.glyph->advance.x/2 - (ruby_last.glyph->advance.x+1)/2; | |
209 | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
210 /* ルビ、本文の横方向の移動 */ |
0 | 211 int ruby_xstart_add = 0, ruby_xend_add = 0, str_xstart_add=0, str_xend_add = 0; |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
212 if (ruby_width+leftmergin+rightmergin <= str_width) { // ルビの方が小さい |
0 | 213 ruby_xstart_add = leftmergin; |
214 ruby_xend_add = str_width-rightmergin-ruby_width; | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
215 } else if (ruby_width <= str_width) { // マージンを減らす必要あり |
0 | 216 leftmergin = (str_width-ruby_width)/2; |
217 ruby_xstart_add = leftmergin; | |
218 ruby_xend_add = str_width-leftmergin-ruby_width; | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
219 } else { // ルビの方が大きい |
0 | 220 int str_count = ruby_firstpos - str_firstpos; |
221 str_xstart_add = ruby_width/str_count/2 - str_first.glyph->advance.x/2; | |
222 str_xend_add = (ruby_width-str_width) - (ruby_width/str_count/2-str_last.glyph->advance.x/2); | |
223 str_width = ruby_width; | |
224 } | |
225 AdjustPosition(str_xstart_add+x, str_xend_add+x, 0, data->begin()+str_firstpos, data->begin()+ruby_firstpos); | |
226 AdjustPosition(ruby_xstart_add+x, ruby_xend_add+x, -ruby_height, data->begin()+ruby_firstpos, data->end()); | |
227 | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
228 /* 本文が一文字ずつ表示されるように glyph の順番を入れかえ、グループ化 */ |
0 | 229 vector<TextGlyph> save; |
230 save.assign(data->begin()+str_firstpos, data->end()); | |
231 iterator it_str = save.begin(); | |
232 iterator it_ruby = save.begin()+(ruby_firstpos-str_firstpos); | |
233 iterator dit = data->begin()+str_firstpos; | |
234 int str_count = it_ruby-it_str; | |
235 int ruby_count = save.end()-it_ruby; | |
236 int i,j = 0; | |
237 for (i=0; i<str_count; i++) { | |
238 iterator charstart = dit; | |
239 int jend = (i+1)*ruby_count/str_count; | |
240 for (; j<jend; j++) { | |
241 *dit++ = *it_ruby++; | |
242 } | |
243 *dit++ = *it_str++; | |
244 SetGroup(charstart, dit); | |
245 } | |
246 x += str_width; | |
247 return it; | |
248 } | |
249 | |
250 | |
251 void TextGlyphStreamHelper::SetGroup(TextGlyphStreamHelper::iterator begin, TextGlyphStreamHelper::iterator end) { | |
252 iterator it; | |
253 for (it = begin; it+1 != end; it++) | |
254 it->flag = TextGlyph::Flag(it->flag |TextGlyph::Group); | |
255 it->flag = TextGlyph::Flag(it->flag & ~TextGlyph::Group); | |
256 return; | |
257 } | |
258 | |
259 void TextGlyphStreamHelper::AdjustPosition(int xstart_add, int xend_add, int y_add, TextGlyphStreamHelper::iterator begin, TextGlyphStreamHelper::iterator end) { | |
260 iterator it; | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
261 /* 文字数を数える */ |
0 | 262 int total_count = 0; |
263 for (it = begin; it != end; it++) { | |
264 if (it->flag & TextGlyph::Group) continue; | |
265 total_count++; | |
266 } | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
267 /* 文字間のギャップを変更 */ |
0 | 268 int incr = 0; |
269 if (total_count != 1) incr = (xend_add - xstart_add) * 256 / (total_count-1); | |
270 int cur = xstart_add * 256; | |
271 for (it = begin; it != end; it++) { | |
272 it->x += cur / 256; | |
273 it->y += y_add; | |
274 if (it->flag & TextGlyph::Group) continue; | |
275 cur += incr; | |
276 } | |
277 return; | |
278 } | |
279 void TextGlyphStreamHelper::CalcHeight(int& ascent_r, int& descent_r, TextGlyphStreamHelper::iterator begin, TextGlyphStreamHelper::iterator end) { | |
280 iterator it; | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
281 /* 最大の descent, ascent を計算 */ |
0 | 282 int ascent = 0; |
283 int descent = 0; | |
284 for (it = begin; it != end; it++) { | |
285 | |
286 int y_top = it->y - it->glyph->bitmap_top; | |
287 int y_bottom = it->y + it->glyph->bitmap.rows - it->glyph->bitmap_top; | |
288 | |
289 if (descent < y_bottom) descent = y_bottom; | |
290 if (ascent < -y_top) ascent = -y_top; | |
291 } | |
292 ascent_r = ascent; | |
293 descent_r = descent; | |
294 return; | |
295 } | |
296 | |
297 int TextGlyphStreamHelper::CharWidth(int code) { | |
298 try { | |
299 XKFont::Glyph* g = face->GlyphLoad(code); | |
300 return g->advance.x; | |
301 } catch(...) { | |
302 return 0; | |
303 } | |
304 } | |
305 | |
306 class TextHorizLayout { | |
307 typedef TextStream::Iterator Iterator; | |
308 | |
309 Iterator pos; | |
310 Iterator end; | |
311 TextGlyphStream* data; | |
312 TextGlyphStreamHelper helper; | |
313 int tab_width; | |
314 int cur_y; | |
315 | |
316 void SetName(void); | |
317 void SetLineHead(void); | |
318 void MakeLine(int line_first, int width, vector<int>& lineheights); | |
319 public: | |
320 TextHorizLayout(XKFont::Font* font); | |
321 void Layout(TextStream& stream, TextGlyphStream& glyph, vector<int>& lineheights, int width); | |
322 }; | |
323 | |
324 TextHorizLayout::TextHorizLayout(XKFont::Font* font) : | |
325 helper(font), tab_width(0), cur_y(0) { | |
326 } | |
327 | |
328 void TextHorizLayout::Layout(TextStream& stream, TextGlyphStream& glyph, vector<int>& lineheights, int width) { | |
329 pos = stream.container.begin(); | |
330 end = stream.container.end(); | |
331 data = &glyph; | |
332 | |
333 helper.Init(data); | |
334 tab_width = 0; | |
335 cur_y = 0; | |
336 int prev_y = 0; | |
337 int line_start = glyph.size(); | |
338 while(pos != end) { | |
339 /* | |
340 if (pos->type == TextElem::glyph) { int c = pos->impl.Glyph.code; char cc[3]={0,0,0};cc[0]=c>>8;cc[1]=c;cout<<"glyph "<<cc<<endl;} | |
341 if (pos->type == TextElem::escape) { cout<<"escape "<<pos->impl.Escape.type<<endl;} | |
342 */ | |
343 SetName(); | |
344 SetLineHead(); | |
345 MakeLine(line_start, width, lineheights); | |
346 if (line_start != glyph.size()) { | |
347 data->back().flag = TextGlyph::Flag(data->back().flag | TextGlyph::PhraseEnd | TextGlyph::LineEnd); | |
348 } | |
349 prev_y = cur_y; | |
350 if (pos != end && pos->type == TextElem::escape && pos->impl.Escape.type == TextElem::ret) pos++; | |
351 line_start = glyph.size(); | |
352 } | |
353 return; | |
354 } | |
355 | |
356 void TextHorizLayout::SetName(void) { | |
357 Iterator it; | |
358 | |
359 tab_width = 0; | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
360 /* 行頭が名前なら、処理開始 */ |
0 | 361 for (; pos != end; pos++) { |
362 if (pos->type == TextElem::escape || pos->type == TextElem::glyph) break; | |
363 int x = 0; | |
364 helper.Add(x, pos, pos+1); | |
365 } | |
366 | |
367 if (pos->type != TextElem::escape || pos->impl.Escape.type != TextElem::name_start) return; | |
368 | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
369 /* 名前をセットし、行頭の「の分を含めてタブ幅を設定する */ |
0 | 370 pos++; |
371 for (it = pos; it != end; it++) { | |
372 if (it->type == TextElem::escape && it->impl.Escape.type == TextElem::name_end) break; | |
373 } | |
374 if (it == end) return; | |
375 int line_firstpos = data->size(); | |
376 pos = helper.Add(tab_width, pos, it); | |
377 pos++; | |
378 helper.SetGroup(data->begin() + line_firstpos, data->end()); | |
379 | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
380 // 行頭の「分を開ける |
0 | 381 try { |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
382 tab_width += helper.CharWidth(0xa1d6); /* 「 */ |
0 | 383 } catch(...) {} |
384 | |
385 return; | |
386 }; | |
387 | |
388 void TextHorizLayout::SetLineHead(void) { | |
389 | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
390 /* 行頭は 「などか? */ |
0 | 391 |
392 for (; pos != end; pos++) { | |
393 if (pos->type == TextElem::escape || pos->type == TextElem::glyph) break; | |
394 int x = 0; | |
395 helper.Add(x, pos, pos+1); | |
396 } | |
397 if (pos->type != TextElem::glyph || Kinsoku(pos->impl.Glyph.code) != KinsokuHead) return; | |
398 | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
399 /* 「なので、処理する */ |
0 | 400 if (tab_width != 0) tab_width -= helper.CharWidth(pos->impl.Glyph.code); |
401 int line_firstpos = data->size(); | |
402 pos = helper.Add(tab_width, pos, pos+1); | |
403 return; | |
404 } | |
405 | |
406 void TextHorizLayout::MakeLine(int line_start, int width, vector<int>& lineheights) { | |
407 | |
408 int x = tab_width; | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
409 /* まず、全文字描画する */ |
0 | 410 while(pos != end) { |
411 pos = helper.Add(x, pos, end); | |
412 if (pos->type == TextElem::escape && pos->impl.Escape.type == TextElem::ruby_start) { | |
413 pos = helper.AddRuby(x, pos, end); | |
414 } | |
415 if (pos != end && pos->type == TextElem::escape) { | |
416 if (pos->impl.Escape.type == TextElem::ret) break; | |
417 if (pos->impl.Escape.type != TextElem::ruby_start) pos++; | |
418 } | |
419 } | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
420 /* 行に分割していく */ |
0 | 421 TextGlyphStream::iterator it_start = data->begin() + line_start; |
422 TextGlyphStream::iterator it_end = data->end(); | |
423 TextGlyphStream::iterator it = it_start; | |
424 | |
425 TextGlyphStream::iterator group_head = it_start; | |
426 int xstart = tab_width; | |
427 int xend = width; | |
428 while(it != it_end) { | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
429 // この行の終わりを決める |
0 | 430 bool is_ruby = false; |
431 TextGlyphStream::iterator it_line_start = it; | |
432 for (; it != it_end; it++) { | |
433 if (it->x + it->glyph->advance.x > xend) break; | |
434 if (it->flag & TextGlyph::Group) is_ruby = true; | |
435 if (!(it->flag & TextGlyph::Group)) group_head = it; | |
436 } | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
437 // 水平移動の大きさを決める。デフォルトでタブ位置まで戻す |
0 | 438 int xadd_start = -xstart + tab_width; |
439 int xadd_end = xadd_start; | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
440 // it == 次行の先頭なので、今行の末尾へ戻す |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
441 // ただし、 最低一文字の表示は保証 |
0 | 442 if (it != it_line_start && it != it_line_start+1 && it != it_end) it--; |
443 if (it != it_end) { | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
444 // グループ化されている文字で終了したら、前の文字に戻す |
0 | 445 if (it->flag & TextGlyph::Group) it = group_head; |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
446 // 次が行頭禁則文字ならこの行に入れる |
0 | 447 if ( (it+1) != it_end && (it+1)->flag & TextGlyph::Kinsoku) it++; |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
448 // 移動する大きさを決める |
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
449 // 行端ぞろえ、行末文字なら半文字分だけ突き出る |
0 | 450 int glyph_xend = it->x + it->glyph->advance.x; |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
451 if (it != it_line_start && (it-1)->flag & TextGlyph::Group) { // グループ化文字の場合、1文字前も見る |
0 | 452 if (glyph_xend < (it-1)->x + (it-1)->glyph->advance.x) |
453 glyph_xend = (it-1)->x + (it-1)->glyph->advance.x; | |
454 } | |
455 xadd_end += xend - glyph_xend; | |
456 if (it->flag & TextGlyph::Kinsoku) | |
457 xadd_end += it->glyph->advance.x / 2; | |
458 } | |
459 if (it != it_end) { | |
460 it->flag = TextGlyph::Flag(it->flag | TextGlyph::LineEnd); | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
461 it++; // it == 次行の先頭へ |
0 | 462 } |
463 int ascent, descent; | |
464 helper.CalcHeight(ascent, descent, it_start, it); | |
465 if (ascent+descent < helper.min_lineheight) { | |
466 int dif = helper.min_lineheight-(ascent+descent); | |
467 ascent += dif/2; | |
468 descent += dif-(dif/2); | |
469 } | |
470 if (is_ruby) ascent+=ruby_lineskip; | |
471 helper.AdjustPosition(xadd_start, xadd_end, cur_y+ascent+1, it_start, it); | |
472 cur_y += ascent + descent + line_skip; | |
473 lineheights.push_back(ascent+descent+line_skip); | |
474 | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
475 /* 次の行へ */ |
0 | 476 if (it != it_end) { |
477 it_start = it; | |
478 group_head = it_start; | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
479 /* 1文字目がグループ化されていれば、グループの先頭文字にする */ |
0 | 480 xstart = it->x; |
481 if (it->flag & TextGlyph::Group) { | |
482 TextGlyphStream::iterator jit; | |
483 for (jit = it; jit != it_end; jit++) { | |
484 if (xstart > jit->x) xstart = jit->x; | |
485 if (!(jit->flag & TextGlyph::Group)) break; | |
486 } | |
487 } | |
488 xend = it->x + width-tab_width; | |
489 } | |
490 } | |
491 return; | |
492 } | |
493 | |
494 namespace XKFont { | |
495 | |
52 | 496 HorizLayout::HorizLayout(const char* fontname, int size) { |
497 font = new Font(fontname, size); | |
498 pimpl = new ::TextHorizLayout(font); | |
499 } | |
0 | 500 |
52 | 501 HorizLayout::~HorizLayout() { |
502 delete pimpl; | |
503 delete font; | |
504 } | |
0 | 505 |
52 | 506 void HorizLayout::Layout(TextStream& stream, TextGlyphStream& glyph, vector<int>& lineheights, int width) { |
507 pimpl->Layout(stream, glyph, lineheights, width); | |
508 }; | |
509 | |
510 TextGlyphStream HorizLayout::Layout(const char* str, int width, int r, int gc, int b) { | |
511 TextStream s; | |
512 s.SetColor(r,gc,b); | |
513 s.Add(str); | |
53
ddbcbd000206
* MuSys, AyuSysConfig, FileSearcher (former FILESEARCHER) and KeyHolder (former KEYHOLDER) are now singletons
thib
parents:
52
diff
changeset
|
514 return Layout(s, width); |
ddbcbd000206
* MuSys, AyuSysConfig, FileSearcher (former FILESEARCHER) and KeyHolder (former KEYHOLDER) are now singletons
thib
parents:
52
diff
changeset
|
515 } |
ddbcbd000206
* MuSys, AyuSysConfig, FileSearcher (former FILESEARCHER) and KeyHolder (former KEYHOLDER) are now singletons
thib
parents:
52
diff
changeset
|
516 |
ddbcbd000206
* MuSys, AyuSysConfig, FileSearcher (former FILESEARCHER) and KeyHolder (former KEYHOLDER) are now singletons
thib
parents:
52
diff
changeset
|
517 TextGlyphStream HorizLayout::Layout(TextStream s, int width) { |
52 | 518 TextGlyphStream g; |
519 vector<int> h; | |
520 Layout(s, g, h, width); | |
521 return g; | |
522 } | |
0 | 523 |
524 }; | |
525 | |
526 int TextGlyphStream::width(void) { | |
527 if (empty()) return 0; | |
528 iterator it; | |
529 int xmax = 0; | |
530 for (it=begin(); it!=end(); it++) { | |
531 int x = it->x + it->glyph->advance.x; | |
532 if (x > xmax) xmax = x; | |
533 } | |
534 return xmax + 1; | |
535 } | |
536 | |
537 int TextGlyphStream::height(void) { | |
538 if (empty()) return 0; | |
539 iterator it; | |
540 int ymax = 0; | |
541 it = end(); | |
542 while(1) { | |
543 it--; | |
544 int y = it->y + it->glyph->bitmap.rows - it->glyph->bitmap_top; | |
545 if (ymax < y) ymax = y; | |
546 if (it == begin()) break; | |
547 if (it->flag & TextGlyph::LineEnd) { | |
65
4416cfac86ae
Convert EUC-JP files to UTF8
Thibaut Girka <thib@sitedethib.com>
parents:
53
diff
changeset
|
548 if (!(it->flag & TextGlyph::PhraseEnd)) break; // PhraseEnd は最後の文字 |
0 | 549 } |
550 } | |
551 return ymax + 1; | |
552 } | |
553 |