Mercurial > otakunoraifu
annotate font/font_layout.cc @ 74:f8751d74918b default tip
Remove “duplicate” functions as they can be remplaced by a nearly-identical existing function.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Sat, 02 Apr 2011 19:13:54 +0200 |
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 |