tdf#62032 use style list level when changing style
[LibreOffice.git] / hwpfilter / source / hbox.cxx
blob2715da1c76bff258b548a2b88300adffee7df364
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "precompile.h"
23 #include "hwpfile.h"
24 #include "hbox.h"
25 #include "hpara.h"
26 #include "hutil.h"
27 #include "htags.h"
28 #include "drawdef.h"
29 #include "hcode.h"
30 #include "datecode.h"
32 #include <rtl/character.hxx>
34 int HBox::boxCount = 0;
36 HBox::HBox(hchar hch)
38 hh = hch;
39 boxCount++;
43 HBox::~HBox()
45 boxCount--;
49 int HBox::WSize()
51 static const int wsize[32] =
53 1, 4, 4, 4, 4, 4, 4, 42, /* dateform */
54 48, 4, 4, 4, 4, 1, 4, 4, /* hidden */
55 4, 4, 4, 4, 4, 4, 12, 5, /* chcompose */
56 3, 3, 123, 4, 32, 4, 2, 2
59 if (hh < 32)
60 return wsize[hh];
61 else
62 return 1;
66 // skip block
67 SkipData::SkipData(hchar hch)
68 : HBox(hch)
72 SkipData::~SkipData()
77 // FieldCode [5]
78 FieldCode::FieldCode()
79 : HBox(CH_FIELD)
80 , location_info(0)
84 FieldCode::~FieldCode()
88 // book mark(6)
89 Bookmark::Bookmark()
90 : HBox(CH_BOOKMARK)
91 , dummy(0)
92 , type(0)
96 Bookmark::~Bookmark()
100 // date format(7)
101 DateFormat::DateFormat()
102 : HBox(CH_DATE_FORM)
103 , dummy(0)
107 // date code(8)
108 DateCode::DateCode()
109 : HBox(CH_DATE_CODE)
110 , format{0}
111 , date{0}
112 , dummy(0)
113 , key(0)
117 const hchar kor_week[] =
119 0xB7A9, 0xB6A9, 0xD1C1, 0xAE81, 0xA1A2, 0x8B71, 0xC9A1
121 const hchar china_week[] =
123 0x4CC8, 0x4BE4, 0x525A, 0x48D8, 0x45AB, 0x4270, 0x50B4
125 const char eng_week[] = { "SunMonTueWedThuFriSat" };
126 const char eng_mon[] = { "JanFebMarAprMayJunJulAugSepOctNovDec" };
127 const char * const en_mon[] =
129 "January", "February", "March", "April", "May", "June", "July",
130 "August", "September", "October", "November", "December"
132 const char * const en_week[] =
134 "Sunday", "Monday", "Tuesday", "Wednesday",
135 "Thursday", "Friday", "Saturday"
138 hchar_string DateCode::GetString()
140 hchar_string ret;
141 const hchar *fmt;
142 int i, num;
143 const char *form;
144 char cbuf[256];
145 bool is_pm, add_zero;
147 add_zero = false;
148 format[DATE_SIZE - 1] = 0;
149 fmt = format[0] ? format : defaultform;
151 for (; *fmt && (static_cast<int>(ret.size()) < DATE_SIZE); fmt++)
153 form = add_zero ? "%02d" : "%d";
155 add_zero = false;
156 is_pm = (date[HOUR] >= 12);
157 *cbuf = 0;
158 num = -1;
160 switch (*fmt)
162 case '0':
163 add_zero = true;
164 break;
165 case '1':
166 num = date[YEAR];
167 form = "%04d";
168 break;
169 case '!':
170 num = date[YEAR] % 100;
171 break;
172 case '2':
173 num = date[MONTH];
174 break;
175 case '@':
177 static_assert((std::size(eng_mon) - 1) / 3 == 12);
178 size_t nIndex = o3tl::make_unsigned(date[MONTH] - 1) % 12;
179 memcpy(cbuf, eng_mon + nIndex * 3, 3);
180 cbuf[3] = '.';
181 cbuf[4] = 0;
182 break;
184 case '*':
186 size_t nIndex = o3tl::make_unsigned(date[MONTH] - 1) % std::size(en_mon);
187 strncat(cbuf, en_mon[nIndex], sizeof(cbuf) - strlen(cbuf) - 1);
188 break;
190 case '3': /* 'D' is day of korean */
191 num = date[DAY];
192 break;
193 case '#':
194 num = date[DAY];
195 switch (date[DAY] % 10)
197 case 1:
198 form = "%dst";
199 break;
200 case 2:
201 form = "%dnd";
202 break;
203 case 3:
204 form = "%drd";
205 break;
206 default:
207 form = "%dth";
208 break;
210 break;
211 case '4':
212 num = date[HOUR] - ((date[HOUR] > 12) ? 12 : 0);
213 break;
214 case '$':
215 num = date[HOUR];
216 break;
217 case '5':
218 case '%':
219 num = date[MIN];
220 break;
221 case '6':
223 size_t nIndex = o3tl::make_unsigned(date[WEEK]) % std::size(kor_week);
224 ret.push_back(kor_week[nIndex]);
225 break;
227 case '^':
229 static_assert((std::size(eng_week) - 1) / 3 == 7);
230 size_t nIndex = o3tl::make_unsigned(date[WEEK]) % 7;
231 memcpy(cbuf, eng_week + nIndex * 3, 3);
232 cbuf[3] = '.';
233 cbuf[4] = 0;
234 break;
236 case '_':
238 size_t nIndex = o3tl::make_unsigned(date[WEEK]) % std::size(en_week);
239 strncat(cbuf, en_week[nIndex], sizeof(cbuf) - strlen(cbuf) - 1);
240 break;
242 case '7':
243 ret.push_back(0xB5A1);
244 ret.push_back(is_pm ? 0xD281 : 0xB8E5);
245 break;
246 case '&':
247 strncat(cbuf, is_pm ? "p.m." : "a.m.", sizeof(cbuf) - strlen(cbuf) - 1);
248 break;
249 case '+':
250 strncat(cbuf, is_pm ? "P.M." : "A.M.", sizeof(cbuf) - strlen(cbuf) - 1);
251 break;
252 case '8': // 2.5 feature
253 case '9':
254 #if 0
255 // LATER
256 mkcurfilename(cbuf, *fmt);
257 for (i = 0; cbuf[i] != 0 && slen > 1; i++)
258 { //for hangle filename
259 if (cbuf[i] & 0x80 && cbuf[i + 1] != 0)
261 *d++ = (cbuf[i] << 8) | cbuf[i + 1];
262 i++;
264 else
265 *d++ = cbuf[i];
266 slen--;
268 #endif
269 cbuf[0] = 0;
270 break;
271 case '~': // 3.0b feature
272 if (fmt[1] == 0)
273 break;
274 fmt++;
275 if (*fmt == '6')
277 size_t nIndex = o3tl::make_unsigned(date[WEEK]) % std::size(china_week);
278 ret.push_back(china_week[nIndex]);
279 break;
281 break;
282 default:
283 if (*fmt == '\\' && *++fmt == 0)
284 goto done;
285 ret.push_back(*fmt);
287 if (num != -1)
288 sprintf(cbuf, form, num);
289 for (i = 0; 0 != cbuf[i]; i++)
291 ret.push_back(*(cbuf + i));
294 done:
295 return ret;
298 // tab(9)
299 Tab::Tab()
300 : HBox(CH_TAB)
301 , width(0)
302 , leader(0)
303 , dummy(0)
307 // floating box
308 FBox::FBox(hchar hch)
309 : HBox(hch)
310 , zorder(0)
311 , option(0)
312 , ctrl_ch(0)
313 , box_xs(0)
314 , box_ys(0)
315 , cap_xs(0)
316 , cap_ys(0)
317 , xs(0)
318 , ys(0)
319 , cap_margin(0)
320 , xpos_type(0)
321 , ypos_type(0)
322 , smart_linesp(0)
323 , boundsy(0)
324 , boundey(0)
325 , boundx(0)
326 , draw(0)
327 , pgx(0)
328 , pgy(0)
329 , pgno(0)
330 , showpg(0)
334 FBox::~FBox()
338 // tbox(10) TABLE BOX MATH BUTTON HYPERTEXT
339 TxtBox::TxtBox()
340 : FBox(CH_TEXT_BOX)
341 , dummy(0)
342 , dummy1(0)
343 , cap_len(0)
344 , next_box(0)
345 , dummy2(0)
346 , reserved1(0)
347 , cap_pos(0)
348 , num(0)
349 , dummy3(0)
350 , baseline(0)
351 , type(0)
352 , nCell(0)
353 , protect(0)
354 , m_pTable(nullptr)
356 reserved[0] = reserved[1] = 0;
359 TxtBox::~TxtBox()
363 // picture(11)
365 Picture::Picture()
366 : FBox(CH_PICTURE)
367 , reserved{0}
368 , dummy(0)
369 , follow_block_size(0)
370 , dummy1(0)
371 , dummy2(0)
372 , reserved1(0)
373 , cap_pos(0)
374 , num(0)
375 , pictype(0)
376 , skip{0}
377 , scale{0}
378 , picinfo{}
379 , reserved3{0}
380 , ishyper(false)
384 Picture::~Picture()
386 if (pictype == PICTYPE_DRAW)
387 delete picinfo.picdraw.hdo;
391 // line(14)
392 // hidden(15)
393 Hidden::~Hidden()
398 // header/footer(16)
399 HeaderFooter::~HeaderFooter()
404 // footnote(17)
405 Footnote::~Footnote()
410 // auto number(18)
411 // new number(19)
412 // show page number (20)
413 // Start/Hide odd-numbered side (21)
415 // mail merge(22)
416 hchar_string MailMerge::GetString()
418 return hchar_string();
422 // character composition(23)
423 // hyphen(24)
424 // toc mark(25)
425 // index mark(26)
426 // outline(28)
428 #define OL_HANGL_JASO 0
429 #define OL_HANGL_KANATA 1
431 static hchar olHanglJaso(int num, int type)
433 static const unsigned char han_init[] =
434 { 0x88, 0x90, 0x94, 0x9c, 0xa0, 0xa4, 0xac, 0xb4, 0xb8, 0xc0, 0xc4, 0xc8, 0xcc, 0xd0 };
435 static const unsigned char jung[] = { 3, 5, 7, 11, 13, 19, 20, 26, 27, 29, 30 };
436 static const unsigned char jung2[] = { 3, 7, 13, 20, 27, 29, 30 };
438 hchar hh = 0;
440 if (type == OL_HANGL_JASO)
442 num = num % (14 + SAL_N_ELEMENTS(jung));
444 if (num < 14)
445 hh = (han_init[num] << 8) | 'A';
446 else
447 hh = (jung[num - 14] << 5) | 0x8401;
449 else
451 if (num < 14)
452 hh = (han_init[num] << 8) | 'a';
453 else
455 int j = (num / 14) % SAL_N_ELEMENTS(jung2);
457 num = num % 14;
458 hh = (han_init[num] << 8) | (jung2[j] << 5) | 1;
461 return hh;
465 static const hchar *GetOutlineStyleChars(int style)
467 static const hchar out_bul_style_entry[5][8] = // extern
469 { // 0 OLSTY_BULLET1
470 0x2f18, 0x2f12, 0x2f08, 0x2f02, 0x2f06, 0x2f00, 0x2043, 0x0000
472 { // 1
473 0x2f18, 0x2f12, 0x2f06, 0x2f00, 0x2f36, 0x2f30, 0x2043, 0x0000
475 { // 2
476 0x2f26, 0x2f20, 0x2f06, 0x2f00, 0x2f16, 0x2f10, 0x2043, 0x0000
478 { // 3
479 0x2f18, 0x2f16, 0x2f12, 0x2f10, 0x2f06, 0x2f00, 0x2043, 0x0000
482 0xAC61, 0xB677, 0xB861, 0xB8F7, 0xB781, 0x0000
485 if (style >= OLSTY_BULLET1 && style <= OLSTY_BULLET5)
486 return out_bul_style_entry[style - OLSTY_BULLET1];
487 return nullptr;
491 static void getOutlineNumStr(int style, int level, int num, hchar * hstr)
493 enum
495 U_ROM = 0x01, L_ROM = 0x02, U_ENG = 0x04, L_ENG = 0x08,
496 HAN = 0x10, NUM = 0x20, L_BR = 0x40, R_BR = 0x80
498 static const unsigned char type_tbl[][MAX_OUTLINE_LEVEL] =
501 U_ROM, HAN, NUM, HAN | R_BR, L_BR | NUM | R_BR,
502 L_BR | HAN | R_BR, L_ROM | R_BR
505 U_ROM, U_ENG, NUM, L_ENG | R_BR, L_BR | NUM | R_BR,
506 L_BR | L_ENG | R_BR, L_ROM | R_BR
509 NUM, HAN, L_BR | NUM | R_BR, L_BR | HAN | R_BR, NUM |
510 R_BR, HAN | R_BR, L_ENG
513 char fmt = type_tbl[style - OLSTY_NUMSIG1][level];
514 char buf[80], *ptr;
516 if (num < 1)
517 num = 1;
518 if (fmt & L_BR)
519 *hstr++ = '(';
520 if (fmt & NUM)
522 sprintf(buf, "%d", num);
523 str2hstr(buf, hstr);
524 hstr += strlen(buf);
526 else if (fmt & (U_ROM | L_ROM))
528 num2roman(num, buf);
529 if (fmt & U_ROM)
531 ptr = buf;
532 while (*ptr)
534 *ptr = sal::static_int_cast<char>(
535 rtl::toAsciiUpperCase(static_cast<unsigned char>(*ptr)));
536 ptr++;
539 str2hstr(buf, hstr);
540 hstr += strlen(buf);
542 else
544 num = (num - 1) % 26;
545 if (fmt & U_ENG)
546 *hstr++ = sal::static_int_cast<hchar>('A' + num);
547 else if (fmt & L_ENG)
548 *hstr++ = sal::static_int_cast<hchar>('a' + num);
549 else if (fmt & HAN)
550 *hstr++ = olHanglJaso(num, OL_HANGL_KANATA);
552 *hstr++ = (fmt & R_BR) ? ')' : '.';
553 *hstr = 0;
557 enum
558 { OUTLINE_ON, OUTLINE_NUM };
560 /* level starts from zero. ex) '1.1.1.' is the level 2.
561 number has the value. ex) '1.2.1' has '1,2,1'
562 style has the value which starts from 1 according to the definition in hbox.h
564 hchar_string Outline::GetUnicode() const
566 const hchar *p;
567 hchar buffer[255];
569 buffer[0] = 0;
570 if (kind == OUTLINE_NUM)
572 int levelnum;
573 switch (shape)
575 case OLSTY_NUMS1:
576 case OLSTY_NUMS2:
578 char cur_num_str[10], buf[80];
579 int i;
581 buf[0] = 0;
582 for (i = 0; i <= level; i++)
584 levelnum = ((number[i] < 1) ? 1 : number[i]);
585 if (shape == OLSTY_NUMS2 && i && i == level)
586 sprintf(cur_num_str, "%d%c", levelnum, 0);
587 else
588 sprintf(cur_num_str, "%d%c", levelnum, '.');
589 strcat(buf, cur_num_str);
591 str2hstr(buf, buffer);
592 return hstr2ucsstr(buffer);
594 case OLSTY_NUMSIG1:
595 case OLSTY_NUMSIG2:
596 case OLSTY_NUMSIG3:
598 getOutlineNumStr(shape, level, number[level], buffer);
599 return hstr2ucsstr(buffer);
601 case OLSTY_BULLET1:
602 case OLSTY_BULLET2:
603 case OLSTY_BULLET3:
604 case OLSTY_BULLET4:
605 case OLSTY_BULLET5:
607 p = GetOutlineStyleChars(shape);
608 buffer[0] = p[level];
609 buffer[1] = 0;
610 return hstr2ucsstr(buffer);
612 case OLSTY_USER:
613 case OLSTY_BULUSER:
615 char dest[80];
616 int l = 0;
617 int i = level;
618 if( deco[i][0] ){
619 buffer[l++] = deco[i][0];
621 /* level starts from zero. ex) '1.1.1.' is the level 2.
622 number has the value. ex) '1.2.1' has '1,2,1'
623 style has the value which starts from 1 according to the definition in hbox.h
625 switch( user_shape[i] )
627 case 0:
628 buffer[l++] = '1' + number[i] - 1;
629 break;
630 case 1: /* Uppercase Roman */
631 case 2: /* Lowercase Roman */
632 num2roman(number[i], dest);
633 if( user_shape[i] == 1 ){
634 char *ptr = dest;
635 while( *ptr )
637 *ptr = sal::static_int_cast<char>(rtl::toAsciiUpperCase(static_cast<unsigned char>(*ptr)));
638 ptr++;
641 str2hstr(dest, buffer + l);
642 l += strlen(dest);
643 break;
644 case 3:
645 buffer[l++] = 'A' + number[i] -1;
646 break;
647 case 4:
648 buffer[l++] = 'a' + number[i] -1;
649 break;
650 case 5:
651 buffer[l++] = olHanglJaso(number[i] -1, OL_HANGL_KANATA);
652 break;
653 case 6:
654 buffer[l++] = olHanglJaso(number[i] -1, OL_HANGL_JASO);
655 break;
656 case 7: /* Chinese numbers: the number represented by the general */
657 buffer[l++] = '1' + number[i] -1;
658 break;
659 case 8: /* Circled numbers */
660 buffer[l++] = 0x2e00 + number[i];
661 break;
662 case 9: /* Circled lowercase alphabet */
663 buffer[l++] = 0x2c20 + number[i];
664 break;
665 case 10: /* Circled Korean Alphabet */
666 buffer[l++] = 0x2c50 + number[i] -1;
667 break;
668 case 11: /* Circled Korean Characters */
669 buffer[l++] = 0x2c40 + number[i] -1;
670 break;
671 case 12: /* Sequenced numbers. */
673 char cur_num_str[10],buf[80];
674 int j;
675 buf[0] = 0;
676 for (j = 0; j <= level; j++)
678 levelnum = ((number[j] < 1) ? 1 : number[j]);
679 if ((j && j == level) || (j == level && deco[i][1]))
680 sprintf(cur_num_str, "%d%c", levelnum, 0);
681 else
682 sprintf(cur_num_str, "%d%c", levelnum, '.');
683 strcat(buf, cur_num_str);
685 str2hstr(buf, buffer + l);
686 l += strlen(buf);
687 break;
689 default:
690 buffer[l++] = user_shape[i];
691 break;
693 if( deco[i][1] ){
694 buffer[l++] = deco[i][1];
696 buffer[l] = 0;
697 return hstr2ucsstr(buffer);
701 return hstr2ucsstr(buffer);
705 /* Bundle of spaces (30) */
706 /* Fixed-width spaces (31) */
708 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */