1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3 * This file is part of the libetonyek project.
4 *
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/.
8 */
9
10 #include <boost/spirit/include/qi.hpp>
11
12 #include <glm/glm.hpp>
13 #include <memory>
14
15 #include "KEY1Parser.h"
16
17 #include "libetonyek_xml.h"
18
19 #include "IWORKDiscardContext.h"
20 #include "IWORKProperties.h"
21 #include "IWORKRecorder.h"
22 #include "IWORKText.h"
23 #include "IWORKTokenizer.h"
24 #include "KEYCollector.h"
25 #include "KEYEnum.h"
26 #include "KEY1ContentElement.h"
27 #include "KEY1Dictionary.h"
28 #include "KEY1DivElement.h"
29 #include "KEY1FillElement.h"
30 #include "KEY1ParserState.h"
31 #include "KEY1SpanElement.h"
32 #include "KEY1StringConverter.h"
33 #include "KEY1StylesContext.h"
34 #include "KEY1TableElement.h"
35 #include "KEY1Token.h"
36 #include "KEY1XMLContextBase.h"
37
38 using boost::optional;
39
40 namespace libetonyek
41 {
42
43 namespace
44 {
45
46 class MetadataElement : public KEY1XMLElementContextBase
47 {
48 public:
49 explicit MetadataElement(KEY1ParserState &state);
50
51 protected:
52 IWORKXMLContextPtr_t element(int name) override;
53 void endOfElement() override;
54
55 private:
56 boost::optional<std::string> m_author;
57 boost::optional<std::string> m_title;
58 boost::optional<std::string> m_keywords;
59 boost::optional<std::string> m_comment;
60 };
61
MetadataElement(KEY1ParserState & state)62 MetadataElement::MetadataElement(KEY1ParserState &state)
63 : KEY1XMLElementContextBase(state)
64 , m_author()
65 , m_title()
66 , m_keywords()
67 , m_comment()
68 {
69 }
70
element(const int name)71 IWORKXMLContextPtr_t MetadataElement::element(const int name)
72 {
73 switch (name)
74 {
75 // find application-name, application-version, time-stamp
76 default:
77 break;
78 }
79
80 return IWORKXMLContextPtr_t();
81 }
82
endOfElement()83 void MetadataElement::endOfElement()
84 {
85 IWORKMetadata metadata;
86
87 if (m_author)
88 metadata.m_author = get(m_author);
89 if (m_title)
90 metadata.m_title = get(m_title);
91 if (m_keywords)
92 metadata.m_keywords = get(m_keywords);
93 if (m_comment)
94 metadata.m_comment = get(m_comment);
95
96 if (isCollector())
97 getCollector().collectMetadata(metadata);
98 }
99
100 }
101
102 namespace
103 {
104
105 class CDATAElement : public KEY1XMLElementContextBase
106 {
107 public:
108 explicit CDATAElement(KEY1ParserState &state, boost::optional<std::string> &description);
109
110 private:
111 IWORKXMLContextPtr_t element(int name) override;
112 void CDATA(const char *value) override;
113
114 private:
115 boost::optional<std::string> &m_description;
116 };
117
CDATAElement(KEY1ParserState & state,boost::optional<std::string> & description)118 CDATAElement::CDATAElement(KEY1ParserState &state, boost::optional<std::string> &description)
119 : KEY1XMLElementContextBase(state)
120 , m_description(description)
121 {
122 }
123
CDATA(const char * value)124 void CDATAElement::CDATA(const char *value)
125 {
126 m_description=value;
127 }
128
129
element(const int)130 IWORKXMLContextPtr_t CDATAElement::element(const int /*name*/)
131 {
132 ETONYEK_DEBUG_MSG(("CDATAElement::element[KEY1Parser.cpp]: unknown element\n"));
133
134 return IWORKXMLContextPtr_t();
135 }
136
137 }
138
139 namespace
140 {
141
142 class TransitionStyleElement : public KEY1XMLElementContextBase
143 {
144 public:
145 explicit TransitionStyleElement(KEY1ParserState &state);
146
147 private:
148 void attribute(int name, const char *value) override;
149 IWORKXMLContextPtr_t element(int name) override;
150
151 private:
152 KEYTransition m_transitionStyle;
153 };
154
TransitionStyleElement(KEY1ParserState & state)155 TransitionStyleElement::TransitionStyleElement(KEY1ParserState &state)
156 : KEY1XMLElementContextBase(state)
157 , m_transitionStyle()
158 {
159 }
160
attribute(const int name,const char * const value)161 void TransitionStyleElement::attribute(const int name, const char *const value)
162 {
163 switch (name)
164 {
165 case KEY1Token::duration :
166 m_transitionStyle.m_duration=try_double_cast(value);
167 break;
168 case KEY1Token::type :
169 switch (getState().getTokenizer().getId(value))
170 {
171 case KEY1Token::none :
172 m_transitionStyle.m_type=KEY_TRANSITION_STYLE_TYPE_NONE;
173 break;
174 case KEY1Token::inherited :
175 m_transitionStyle.m_type=KEY_TRANSITION_STYLE_TYPE_INHERITED;
176 break;
177 default :
178 {
179 m_transitionStyle.m_type=KEY_TRANSITION_STYLE_TYPE_NAMED;
180 m_transitionStyle.m_name=value;
181 static bool first=true;
182 if (first)
183 {
184 first=false;
185 ETONYEK_DEBUG_MSG(("TransitionStyleElement::attribute[KEY1Parser.cpp]: find some unexpected type=%s\n", value));
186 }
187 break;
188 }
189 }
190 break;
191 default :
192 ETONYEK_DEBUG_MSG(("TransitionStyleElement::attribute[KEY1Parser.cpp]: unexpected attribute\n"));
193 break;
194 }
195 }
196
element(const int)197 IWORKXMLContextPtr_t TransitionStyleElement::element(const int /*name*/)
198 {
199 ETONYEK_DEBUG_MSG(("TransitionStyleElement::element[KEY1Parser.cpp]: unknown element\n"));
200 return IWORKXMLContextPtr_t();
201 }
202 }
203
204 namespace
205 {
206 struct BulletStyle
207 {
BulletStylelibetonyek::__anon6ee760350411::BulletStyle208 BulletStyle()
209 : m_relative(true)
210 , m_size()
211 {
212 }
213 bool m_relative;
214 boost::optional<double> m_size;
215 };
216 }
217
218 namespace
219 {
220
221 class BulletCharacterStyleElement : public KEY1XMLElementContextBase
222 {
223 public:
224 explicit BulletCharacterStyleElement(KEY1ParserState &state);
225
226 private:
227 void attribute(int name, const char *value) override;
228 IWORKXMLContextPtr_t element(int name) override;
229
230 private:
231 BulletStyle m_bulletStyle;
232 };
233
BulletCharacterStyleElement(KEY1ParserState & state)234 BulletCharacterStyleElement::BulletCharacterStyleElement(KEY1ParserState &state)
235 : KEY1XMLElementContextBase(state)
236 , m_bulletStyle()
237 {
238 }
239
attribute(const int name,const char * const value)240 void BulletCharacterStyleElement::attribute(const int name, const char *const value)
241 {
242 switch (name)
243 {
244 case KEY1Token::size_technique :
245 switch (getState().getTokenizer().getId(value))
246 {
247 case KEY1Token::relative :
248 m_bulletStyle.m_relative=true;
249 break;
250 default :
251 ETONYEK_DEBUG_MSG(("BulletCharacterStyleElement::attribute[KEY1Parser.cpp]: unexpected size technique %s\n", value));
252 break;
253 }
254 break;
255 case KEY1Token::size :
256 m_bulletStyle.m_size=try_double_cast(value);
257 break;
258 default :
259 ETONYEK_DEBUG_MSG(("BulletCharacterStyleElement::attribute[KEY1Parser.cpp]: unexpected attribute\n"));
260 break;
261 }
262 }
263
element(const int name)264 IWORKXMLContextPtr_t BulletCharacterStyleElement::element(const int name)
265 {
266 switch (name)
267 {
268 case KEY1Token::bullet_characters | KEY1Token::NS_URI_KEY : // README
269 break;
270 default :
271 ETONYEK_DEBUG_MSG(("BulletCharacterStyleElement::element[KEY1Parser.cpp]: unknown element\n"));
272 break;
273 }
274
275 return IWORKXMLContextPtr_t();
276 }
277 }
278
279 namespace
280 {
281
282 class BulletElement : public KEY1XMLElementContextBase
283 {
284 public:
285 explicit BulletElement(KEY1ParserState &state);
286
287 private:
288 void attribute(int name, const char *value) override;
289 IWORKXMLContextPtr_t element(int name) override;
290 void endOfElement() override;
291
292 void ensureOpened();
293
294 private:
295 KEY1Bullet m_bullet;
296 bool m_opened;
297 };
298
BulletElement(KEY1ParserState & state)299 BulletElement::BulletElement(KEY1ParserState &state)
300 : KEY1XMLElementContextBase(state)
301 , m_bullet()
302 , m_opened(false)
303 {
304 }
305
attribute(const int name,const char * const value)306 void BulletElement::attribute(const int name, const char *const value)
307 {
308 switch (name)
309 {
310 case KEY1Token::level :
311 m_bullet.m_level=try_int_cast(value);
312 break;
313 case KEY1Token::marker_type :
314 switch (getState().getTokenizer().getId(value))
315 {
316 case KEY1Token::none :
317 m_bullet.m_type=KEY1_BULLETTYPE_NONE;
318 break;
319 case KEY1Token::character :
320 m_bullet.m_type=KEY1_BULLETTYPE_CHARACTER;
321 break;
322 case KEY1Token::image :
323 m_bullet.m_type=KEY1_BULLETTYPE_IMAGE;
324 break;
325 case KEY1Token::inherited :
326 m_bullet.m_type=KEY1_BULLETTYPE_INHERITED;
327 break;
328 case KEY1Token::sequence :
329 m_bullet.m_type=KEY1_BULLETTYPE_SEQUENCE;
330 break;
331 default :
332 ETONYEK_DEBUG_MSG(("BulletElement::attribute[KEY1Parser.cpp]: unexpected type %s\n", value));
333 break;
334 }
335 break;
336 case KEY1Token::spacing :
337 m_bullet.m_spacing=try_double_cast(value);
338 break;
339 default :
340 ETONYEK_DEBUG_MSG(("BulletElement::attribute[KEY1Parser.cpp]: unexpected attribute\n"));
341 break;
342 }
343 }
344
element(const int name)345 IWORKXMLContextPtr_t BulletElement::element(const int name)
346 {
347 ensureOpened();
348 switch (name)
349 {
350 case KEY1Token::character_bullet_style | KEY1Token::NS_URI_KEY :
351 return std::make_shared<BulletCharacterStyleElement>(getState());
352 case KEY1Token::image_bullet_style | KEY1Token::NS_URI_KEY : // README
353 case KEY1Token::sequence_bullet_style | KEY1Token::NS_URI_KEY : // README
354 break;
355 case KEY1Token::content | KEY1Token::NS_URI_KEY :
356 return std::make_shared<KEY1ContentElement>(getState());
357 default :
358 ETONYEK_DEBUG_MSG(("BulletElement::element[KEY1Parser.cpp]: unknown element\n"));
359 break;
360 }
361
362 return IWORKXMLContextPtr_t();
363 }
364
endOfElement()365 void BulletElement::endOfElement()
366 {
367 if (!m_opened) return;
368 getState().closeBullet();
369 m_opened=false;
370 }
371
ensureOpened()372 void BulletElement::ensureOpened()
373 {
374 if (m_opened) return;
375 getState().openBullet(m_bullet);
376 m_opened=true;
377 }
378
379 }
380
381 namespace
382 {
383
384 class BulletsElement : public KEY1XMLElementContextBase
385 {
386 public:
387 explicit BulletsElement(KEY1ParserState &state, bool prototype);
388
389 private:
390 void startOfElement() override;
391 IWORKXMLContextPtr_t element(int name) override;
392 void endOfElement() override;
393
394 private:
395 bool m_prototype;
396 };
397
BulletsElement(KEY1ParserState & state,bool prototype)398 BulletsElement::BulletsElement(KEY1ParserState &state, bool prototype)
399 : KEY1XMLElementContextBase(state)
400 , m_prototype(prototype)
401 {
402 }
403
startOfElement()404 void BulletsElement::startOfElement()
405 {
406 getState().pushIsPrototype(m_prototype);
407 getState().openBullets();
408 }
409
element(const int name)410 IWORKXMLContextPtr_t BulletsElement::element(const int name)
411 {
412 switch (name)
413 {
414 case KEY1Token::bullet | KEY1Token::NS_URI_KEY :
415 return std::make_shared<BulletElement>(getState());
416 default :
417 ETONYEK_DEBUG_MSG(("BulletsElement::element[KEY1Parser.cpp]: unknown element\n"));
418 break;
419 }
420
421 return IWORKXMLContextPtr_t();
422 }
423
endOfElement()424 void BulletsElement::endOfElement()
425 {
426 getState().closeBullets();
427 getState().popIsPrototype();
428 }
429
430 }
431
432 namespace
433 {
434
435 class BasicShapeElement : public KEY1XMLElementContextBase
436 {
437 public:
438 explicit BasicShapeElement(KEY1ParserState &state);
439
440 protected:
441 void attribute(int name, const char *value) override;
442 void startOfElement() override;
443 IWORKXMLContextPtr_t element(int name) override;
444 void endOfElement() override;
445
getStyle() const446 IWORKStylePtr_t getStyle() const
447 {
448 return m_style;
449 }
450 private:
451 IWORKStylePtr_t m_style;
452 boost::optional<IWORKColor> m_strokeColor;
453 boost::optional<double> m_strokeWidth;
454 boost::optional<double> m_opacity;
455 };
456
BasicShapeElement(KEY1ParserState & state)457 BasicShapeElement::BasicShapeElement(KEY1ParserState &state)
458 : KEY1XMLElementContextBase(state)
459 , m_style()
460 , m_strokeColor()
461 , m_strokeWidth()
462 , m_opacity()
463 {
464 }
465
attribute(const int name,const char * const value)466 void BasicShapeElement::attribute(const int name, const char *const value)
467 {
468 switch (name)
469 {
470 case KEY1Token::id :
471 setId(value);
472 break;
473 case KEY1Token::opacity :
474 m_opacity=try_double_cast(value);
475 break;
476 case KEY1Token::stroke_color :
477 m_strokeColor=KEY1StringConverter<IWORKColor>::convert(value);
478 break;
479 case KEY1Token::stroke_width :
480 m_strokeWidth=try_double_cast(value);
481 break;
482 default :
483 ETONYEK_DEBUG_MSG(("BasicShapeElement::attribute[KEY1Parser.cpp]: unexpected attribute\n"));
484 break;
485 }
486 }
487
startOfElement()488 void BasicShapeElement::startOfElement()
489 {
490 }
491
element(const int name)492 IWORKXMLContextPtr_t BasicShapeElement::element(const int name)
493 {
494 switch (name)
495 {
496 case KEY1Token::styles | KEY1Token::NS_URI_KEY :
497 return std::make_shared<KEY1StylesContext>(getState(), m_style, IWORKStylePtr_t());
498 default :
499 ETONYEK_DEBUG_MSG(("BasicShapeElement::element[KEY1Parser.cpp]: unknown element\n"));
500 break;
501 }
502 return IWORKXMLContextPtr_t();
503 }
504
endOfElement()505 void BasicShapeElement::endOfElement()
506 {
507 if (getState().m_isPrototype&& (!m_strokeColor && !m_strokeWidth && !m_opacity))
508 return;
509 if (!m_style)
510 m_style = std::make_shared<IWORKStyle>(IWORKPropertyMap(), boost::none, IWORKStylePtr_t());
511 if (m_opacity)
512 m_style->getPropertyMap().put<property::Opacity>(get(m_opacity));
513 if (m_strokeColor || m_strokeWidth)
514 {
515 IWORKStroke stroke;
516 if (m_style->has<property::Stroke>())
517 stroke=m_style->get<property::Stroke>();
518 else
519 stroke.m_pattern.m_type = IWORK_STROKE_TYPE_SOLID;
520 if (m_strokeColor) stroke.m_color=get(m_strokeColor);
521 if (m_strokeWidth) stroke.m_width=get(m_strokeWidth);
522 m_style->getPropertyMap().put<property::Stroke>(stroke);
523 }
524 }
525
526 }
527
528 namespace
529 {
530
531 class ImageElement : public BasicShapeElement
532 {
533 public:
534 explicit ImageElement(KEY1ParserState &state);
535
536 private:
537 void attribute(int name, const char *value) override;
538 void startOfElement() override;
539 void endOfElement() override;
540 private:
541 boost::optional<std::string> m_displayName;
542 boost::optional<std::string> m_imageName;
543 bool m_lockAspectRatio;
544 bool m_locked;
545 boost::optional<IWORKSize> m_naturalSize;
546 boost::optional<glm::dmat3> m_transformation;
547 };
548
ImageElement(KEY1ParserState & state)549 ImageElement::ImageElement(KEY1ParserState &state)
550 : BasicShapeElement(state)
551 , m_displayName()
552 , m_imageName()
553 , m_lockAspectRatio(false)
554 , m_locked(false)
555 , m_naturalSize()
556 , m_transformation()
557 {
558 }
559
attribute(const int name,const char * const value)560 void ImageElement::attribute(const int name, const char *const value)
561 {
562 switch (name)
563 {
564 case KEY1Token::display_name :
565 m_displayName=value;
566 break;
567 case KEY1Token::image_data :
568 m_imageName=value;
569 break;
570 case KEY1Token::locked :
571 m_locked = bool_cast(value);
572 break;
573 case KEY1Token::lock_aspect_ratio :
574 m_lockAspectRatio = bool_cast(value);
575 break;
576 case KEY1Token::natural_size :
577 m_naturalSize = KEY1StringConverter<IWORKSize>::convert(value);
578 break;
579 case KEY1Token::transformation :
580 m_transformation=KEY1StringConverter<glm::dmat3>::convert(value);
581 break;
582 case KEY1Token::byte_size : // the image size
583 break;
584 default :
585 BasicShapeElement::attribute(name,value);
586 break;
587 }
588 }
589
startOfElement()590 void ImageElement::startOfElement()
591 {
592 BasicShapeElement::startOfElement();
593 if (!getState().m_isPrototype&& isCollector())
594 getCollector().startLevel();
595 }
596
endOfElement()597 void ImageElement::endOfElement()
598 {
599 BasicShapeElement::endOfElement();
600 IWORKMediaContentPtr_t content;
601
602 if (m_imageName)
603 {
604 content = std::make_shared<IWORKMediaContent>();
605 content->m_data = std::make_shared<IWORKData>();
606 content->m_data->m_stream.reset(getState().getParser().getPackage()->getSubStreamByName(get(m_imageName).c_str()));
607 content->m_size=m_naturalSize;
608 }
609 IWORKGeometryPtr_t geometry;
610 if (m_transformation && m_naturalSize)
611 {
612 geometry = std::make_shared<IWORKGeometry>();
613 glm::dvec3 pos=get(m_transformation)*glm::dvec3(0,0,1);
614 geometry->m_position=IWORKPosition(pos[0],pos[1]);
615 glm::dvec3 dim=get(m_transformation)*glm::dvec3(get(m_naturalSize).m_width,get(m_naturalSize).m_height,0);
616 geometry->m_size=IWORKSize(dim[0],dim[1]);
617 }
618 if (getId() && content)
619 getState().getDictionary().m_images[get(getId())]=content;
620
621 IWORKStylePtr_t style=getStyle();
622 getState().getDictionary().storeImageStyle(style, getState().m_isPrototype);
623 if (!getState().m_isPrototype&& isCollector())
624 {
625 if (geometry && content)
626 {
627 getCollector().collectGeometry(geometry);
628 getCollector().setGraphicStyle(style);
629 getCollector().collectImage(content, IWORKGeometryPtr_t(), boost::none, m_locked);
630 }
631 getCollector().endLevel();
632 }
633 }
634 }
635
636 namespace
637 {
638
639 class LineElement : public BasicShapeElement
640 {
641 public:
642 explicit LineElement(KEY1ParserState &state);
643
644 private:
645 void attribute(int name, const char *value) override;
646 void startOfElement() override;
647 void endOfElement() override;
648 private:
649 boost::optional<IWORKPosition> m_head;
650 boost::optional<IWORKPosition> m_tail;
651 };
652
LineElement(KEY1ParserState & state)653 LineElement::LineElement(KEY1ParserState &state)
654 : BasicShapeElement(state)
655 , m_head()
656 , m_tail()
657 {
658 }
659
attribute(const int name,const char * const value)660 void LineElement::attribute(const int name, const char *const value)
661 {
662 switch (name)
663 {
664 case KEY1Token::head :
665 m_head=KEY1StringConverter<IWORKPosition>::convert(value);
666 break;
667 case KEY1Token::tail :
668 m_tail=KEY1StringConverter<IWORKPosition>::convert(value);
669 break;
670 default :
671 BasicShapeElement::attribute(name,value);
672 break;
673 }
674 }
675
startOfElement()676 void LineElement::startOfElement()
677 {
678 BasicShapeElement::startOfElement();
679 if (!getState().m_isPrototype&& isCollector())
680 getCollector().startLevel();
681 }
682
endOfElement()683 void LineElement::endOfElement()
684 {
685 BasicShapeElement::endOfElement();
686 IWORKLinePtr_t line(new IWORKLine());
687 if (m_tail)
688 {
689 line->m_x1 = get(m_tail).m_x;
690 line->m_y1 = get(m_tail).m_y;
691 }
692 if (m_head)
693 {
694 line->m_x2 = get(m_head).m_x;
695 line->m_y2 = get(m_head).m_y;
696 }
697 IWORKStylePtr_t style=getStyle();
698 getState().getDictionary().storeLineStyle(style, getState().m_isPrototype);
699 if (!getState().m_isPrototype&& isCollector())
700 {
701 getCollector().setGraphicStyle(style);
702 getCollector().collectLine(line);
703 getCollector().endLevel();
704 }
705 }
706 }
707
708 namespace
709 {
710
711 class ShapeElement : public BasicShapeElement
712 {
713 public:
714 explicit ShapeElement(KEY1ParserState &state);
715
716 private:
717 void attribute(int name, const char *value) override;
718 void startOfElement() override;
719 void endOfElement() override;
720 private:
721 IWORKPathPtr_t m_path;
722 boost::optional<glm::dmat3> m_transformation;
723 };
724
ShapeElement(KEY1ParserState & state)725 ShapeElement::ShapeElement(KEY1ParserState &state)
726 : BasicShapeElement(state)
727 , m_path()
728 , m_transformation()
729 {
730 }
731
attribute(const int name,const char * const value)732 void ShapeElement::attribute(const int name, const char *const value)
733 {
734 switch (name)
735 {
736 case KEY1Token::path :
737 try
738 {
739 m_path = std::make_shared<IWORKPath>(value);
740 }
741 catch (const IWORKPath::InvalidException &)
742 {
743 ETONYEK_DEBUG_MSG(("ShapeElement::attribute[KEY1Parser.cpp]: '%s' is not a valid path\n", value));
744 }
745 break;
746 case KEY1Token::transformation :
747 m_transformation=KEY1StringConverter<glm::dmat3>::convert(value);
748 break;
749 default :
750 BasicShapeElement::attribute(name, value);
751 break;
752 }
753 }
754
startOfElement()755 void ShapeElement::startOfElement()
756 {
757 BasicShapeElement::startOfElement();
758 if (!getState().m_isPrototype&& isCollector())
759 getCollector().startLevel();
760 }
761
endOfElement()762 void ShapeElement::endOfElement()
763 {
764 BasicShapeElement::endOfElement();
765 IWORKStylePtr_t style=getStyle();
766 getState().getDictionary().storeShapeStyle(style, getState().m_isPrototype);
767 if (!getState().m_isPrototype&& isCollector())
768 {
769 if (m_path)
770 {
771 getCollector().setGraphicStyle(style);
772 if (m_transformation)
773 *m_path *= get(m_transformation);
774 getCollector().collectBezier(m_path);
775 getCollector().collectShape();
776 }
777 getCollector().endLevel();
778 }
779 }
780 }
781
782 namespace
783 {
784 class TextAttributesElement : public KEY1XMLElementContextBase
785 {
786 public:
787 TextAttributesElement(KEY1ParserState &state, IWORKStylePtr_t &spanStyle, IWORKStylePtr_t &divStyle);
788
789 protected:
790 void attribute(int name, const char *value) override;
791 IWORKXMLContextPtr_t element(int name) override;
792 void endOfElement() override;
793
794 private:
795 KEY1DivStyle m_divStyle;
796 KEY1SpanStyle m_spanStyle;
797
798 IWORKStylePtr_t &m_divStylePtr;
799 IWORKStylePtr_t &m_spanStylePtr;
800 };
801
TextAttributesElement(KEY1ParserState & state,IWORKStylePtr_t & spanStyle,IWORKStylePtr_t & divStyle)802 TextAttributesElement::TextAttributesElement(KEY1ParserState &state, IWORKStylePtr_t &spanStyle, IWORKStylePtr_t &divStyle)
803 : KEY1XMLElementContextBase(state)
804 , m_divStyle(state, IWORKStylePtr_t())
805 , m_spanStyle(state, IWORKStylePtr_t())
806 , m_divStylePtr(divStyle)
807 , m_spanStylePtr(spanStyle)
808 {
809 }
810
attribute(const int name,const char * const value)811 void TextAttributesElement::attribute(const int name, const char *const value)
812 {
813 if (m_divStyle.readAttribute(name, value) ||
814 m_spanStyle.readAttribute(name, value))
815 return;
816 switch (name)
817 {
818 case KEY1Token::id :
819 setId(value);
820 break;
821 default:
822 ETONYEK_DEBUG_MSG(("TextAttributesElement::attribute[KEY1Parser.cpp] attribute with value=%s\n", value));
823 }
824 }
825
element(const int name)826 IWORKXMLContextPtr_t TextAttributesElement::element(const int name)
827 {
828 switch (name)
829 {
830 default:
831 ETONYEK_DEBUG_MSG(("TextAttributesElement::element[KEY1Parser.cpp]: unknown element\n"));
832 }
833 return IWORKXMLContextPtr_t();
834 }
835
endOfElement()836 void TextAttributesElement::endOfElement()
837 {
838 m_divStylePtr = m_divStyle.getStyle();
839 m_spanStylePtr = m_spanStyle.getStyle();
840 }
841
842 }
843
844 namespace
845 {
846 class PlaceholderElement : public BasicShapeElement
847 {
848 public:
849 explicit PlaceholderElement(KEY1ParserState &state);
850
851 KEYPlaceholderPtr_t getPlaceholder();
852
853 protected:
854 void attribute(int name, const char *value) override;
855 IWORKXMLContextPtr_t element(int name) override;
856
857 private:
858 boost::optional<IWORKPosition> m_location;
859 boost::optional<IWORKSize> m_size;
860 IWORKStylePtr_t m_paragraphStyle;
861 IWORKStylePtr_t m_spanStyle;
862 boost::optional<IWORKVerticalAlignment> m_verticalAlignment;
863 boost::optional<bool> m_visible;
864 };
865
PlaceholderElement(KEY1ParserState & state)866 PlaceholderElement::PlaceholderElement(KEY1ParserState &state)
867 : BasicShapeElement(state)
868 , m_location()
869 , m_size()
870 , m_paragraphStyle()
871 , m_spanStyle()
872 , m_verticalAlignment()
873 , m_visible()
874 {
875 }
876
attribute(const int name,const char * const value)877 void PlaceholderElement::attribute(const int name, const char *const value)
878 {
879 switch (name)
880 {
881 case KEY1Token::location :
882 m_location=KEY1StringConverter<IWORKPosition>::convert(value);
883 break;
884 case KEY1Token::size :
885 m_size=KEY1StringConverter<IWORKSize>::convert(value);
886 break;
887 case KEY1Token::vertical_alignment :
888 switch (getState().getTokenizer().getId(value))
889 {
890 case KEY1Token::bottom :
891 m_verticalAlignment = IWORK_VERTICAL_ALIGNMENT_BOTTOM;
892 break;
893 case KEY1Token::middle :
894 m_verticalAlignment = IWORK_VERTICAL_ALIGNMENT_MIDDLE;
895 break;
896 case KEY1Token::top :
897 m_verticalAlignment = IWORK_VERTICAL_ALIGNMENT_TOP;
898 break;
899 case KEY1Token::tracks_master :
900 break;
901 default :
902 ETONYEK_DEBUG_MSG(("PlaceHolderElement::attribute[KEY1Parser.cpp]: unexpected vertical align %s\n", value));
903 break;
904 }
905 break;
906 case KEY1Token::visibility :
907 switch (getState().getTokenizer().getId(value))
908 {
909 case KEY1Token::hidden :
910 m_visible = false;
911 break;
912 case KEY1Token::visible :
913 m_visible = true;
914 break;
915 case KEY1Token::tracks_master :
916 break;
917 default :
918 ETONYEK_DEBUG_MSG(("PlaceHolderElement::attribute[KEY1Parser.cpp]: unexpected visibily align %s\n", value));
919 break;
920 }
921 break;
922 default :
923 BasicShapeElement::attribute(name, value);
924 break;
925 }
926 }
927
element(const int name)928 IWORKXMLContextPtr_t PlaceholderElement::element(const int name)
929 {
930 switch (name)
931 {
932 case KEY1Token::text_attributes | KEY1Token::NS_URI_KEY :
933 return std::make_shared<TextAttributesElement>(getState(), m_spanStyle, m_paragraphStyle);
934 default:
935 break;
936 }
937 return BasicShapeElement::element(name);
938 }
939
getPlaceholder()940 KEYPlaceholderPtr_t PlaceholderElement::getPlaceholder()
941 {
942 KEYPlaceholderPtr_t res(new KEYPlaceholder);
943 res->m_style = getStyle();
944 res->m_paragraphStyle = m_paragraphStyle;
945 res->m_spanStyle = m_spanStyle;
946 if (m_location && m_size)
947 {
948 IWORKGeometryPtr_t geometry(new IWORKGeometry);
949 geometry->m_position=get(m_location);
950 geometry->m_naturalSize=geometry->m_size=get(m_size);
951 res->m_geometry=geometry;
952 }
953 res->m_visible=m_visible;
954
955 return res;
956 }
957
958 }
959
960 namespace
961 {
962 class BodyElement : public PlaceholderElement
963 {
964 public:
965 explicit BodyElement(KEY1ParserState &state);
966
967 private:
968 void attribute(int name, const char *value) override;
969 void endOfElement() override;
970 private:
971 std::deque<double> m_indents;
972 };
973
BodyElement(KEY1ParserState & state)974 BodyElement::BodyElement(KEY1ParserState &state)
975 : PlaceholderElement(state)
976 , m_indents()
977 {
978 }
979
attribute(const int name,const char * const value)980 void BodyElement::attribute(const int name, const char *const value)
981 {
982 switch (name)
983 {
984 case KEY1Token::bullet_indentation :
985 {
986 std::string val(value);
987 std::string::const_iterator it(val.begin()), end(val.end());
988
989 namespace ascii = boost::spirit::ascii;
990 namespace qi = boost::spirit::qi;
991 if (qi::phrase_parse(it, end, qi::double_ >> *(qi::double_), ascii::space, m_indents) && it==end)
992 ;
993 else
994 {
995 ETONYEK_DEBUG_MSG(("BodyElement::attribute[KEY1Parser.cpp]: unexpected bullet indentation %s\n", value));
996 }
997 break;
998 }
999 default :
1000 PlaceholderElement::attribute(name, value);
1001 }
1002 }
1003
endOfElement()1004 void BodyElement::endOfElement()
1005 {
1006 KEYPlaceholderPtr_t placeHolder=getPlaceholder();
1007 if (!placeHolder) return;
1008 placeHolder->m_bulletIndentations=m_indents;
1009 getState().getDictionary().storeBodyPlaceholder(placeHolder);
1010 }
1011 }
1012
1013 namespace
1014 {
1015 class PageNumberElement : public PlaceholderElement
1016 {
1017 public:
1018 explicit PageNumberElement(KEY1ParserState &state);
1019
1020 private:
1021 void endOfElement() override;
1022 private:
1023 };
1024
PageNumberElement(KEY1ParserState & state)1025 PageNumberElement::PageNumberElement(KEY1ParserState &state)
1026 : PlaceholderElement(state)
1027 {
1028 }
1029
endOfElement()1030 void PageNumberElement::endOfElement()
1031 {
1032 getState().getDictionary().storePageNumberPlaceholder(getPlaceholder());
1033 }
1034 }
1035
1036 namespace
1037 {
1038 class TitleElement : public PlaceholderElement
1039 {
1040 public:
1041 explicit TitleElement(KEY1ParserState &state);
1042
1043 private:
1044 void endOfElement() override;
1045 private:
1046 };
1047
TitleElement(KEY1ParserState & state)1048 TitleElement::TitleElement(KEY1ParserState &state)
1049 : PlaceholderElement(state)
1050 {
1051 }
1052
endOfElement()1053 void TitleElement::endOfElement()
1054 {
1055 getState().getDictionary().storeTitlePlaceholder(getPlaceholder());
1056 }
1057 }
1058
1059 namespace
1060 {
1061
1062 class TextboxElement : public BasicShapeElement
1063 {
1064 public:
1065 explicit TextboxElement(KEY1ParserState &state);
1066
1067 private:
1068 void attribute(int name, const char *value) override;
1069 void startOfElement() override;
1070 IWORKXMLContextPtr_t element(int name) override;
1071 void endOfElement() override;
1072 private:
1073 boost::optional<IWORKSize> m_size;
1074 boost::optional<glm::dmat3> m_transformation;
1075 boost::optional<bool> m_growHorizontally;
1076 };
1077
TextboxElement(KEY1ParserState & state)1078 TextboxElement::TextboxElement(KEY1ParserState &state)
1079 : BasicShapeElement(state)
1080 , m_size()
1081 , m_transformation()
1082 , m_growHorizontally()
1083 {
1084 }
1085
attribute(const int name,const char * const value)1086 void TextboxElement::attribute(const int name, const char *const value)
1087 {
1088 switch (name)
1089 {
1090 case KEY1Token::grow_horizontally :
1091 m_growHorizontally = try_bool_cast(value);
1092 break;
1093 case KEY1Token::size :
1094 m_size=KEY1StringConverter<IWORKSize>::convert(value);
1095 break;
1096 case KEY1Token::transformation :
1097 m_transformation=KEY1StringConverter<glm::dmat3>::convert(value);
1098 break;
1099 default :
1100 BasicShapeElement::attribute(name, value);
1101 break;
1102 }
1103 }
1104
startOfElement()1105 void TextboxElement::startOfElement()
1106 {
1107 BasicShapeElement::startOfElement();
1108 if (!getState().m_isPrototype&& isCollector())
1109 {
1110 getCollector().startLevel();
1111 assert(!getState().m_currentText);
1112 getState().m_currentText = getCollector().createText(getState().m_langManager);
1113 }
1114 }
1115
element(const int name)1116 IWORKXMLContextPtr_t TextboxElement::element(const int name)
1117 {
1118 switch (name)
1119 {
1120 case KEY1Token::content | KEY1Token::NS_URI_KEY :
1121 return std::make_shared<KEY1ContentElement>(getState());
1122 default:
1123 break;
1124 }
1125 return BasicShapeElement::element(name);
1126 }
1127
endOfElement()1128 void TextboxElement::endOfElement()
1129 {
1130 BasicShapeElement::endOfElement();
1131 IWORKStylePtr_t style=getStyle();
1132 getState().getDictionary().storeTextboxStyle(style, getState().m_isPrototype);
1133 if (!getState().m_isPrototype && isCollector())
1134 {
1135 getCollector().setGraphicStyle(style);
1136 if (m_transformation && m_size)
1137 {
1138 IWORKGeometryPtr_t geometry(new IWORKGeometry);
1139 glm::dvec3 pos=get(m_transformation)*glm::dvec3(0,0,1);
1140 geometry->m_position=IWORKPosition(pos[0],pos[1]);
1141 glm::dvec3 dim=get(m_transformation)*glm::dvec3(get(m_size).m_width,get(m_size).m_height,0);
1142 geometry->m_naturalSize=geometry->m_size=IWORKSize(dim[0],dim[1]);
1143 getCollector().collectGeometry(geometry);
1144 }
1145 IWORKPathPtr_t path=makeRoundedRectanglePath(/*m_size ? get(m_size) : */IWORKSize(1,1), 0);
1146 getCollector().collectBezier(path);
1147 if (bool(getState().m_currentText) && !getState().m_currentText->empty())
1148 getCollector().collectText(getState().m_currentText);
1149 getState().m_currentText.reset();
1150 getCollector().collectShape();
1151
1152 getCollector().endLevel();
1153 }
1154 }
1155 }
1156
1157 namespace
1158 {
1159
1160 class PluginDataElement : public KEY1XMLElementContextBase
1161 {
1162 public:
1163 PluginDataElement(KEY1ParserState &state, boost::optional<IWORKSize> &size, bool prototype);
1164
1165 protected:
1166 void attribute(int name, const char *value) override;
1167 void startOfElement() override;
1168 IWORKXMLContextPtr_t element(int name) override;
1169 void endOfElement() override;
1170
1171 private:
1172 bool m_prototype;
1173 boost::optional<IWORKSize> &m_size;
1174 };
1175
PluginDataElement(KEY1ParserState & state,boost::optional<IWORKSize> & size,bool prototype)1176 PluginDataElement::PluginDataElement(KEY1ParserState &state, boost::optional<IWORKSize> &size, bool prototype)
1177 : KEY1XMLElementContextBase(state)
1178 , m_prototype(prototype)
1179 , m_size(size)
1180 {
1181 }
1182
1183 #ifndef DEBUG
attribute(const int name,const char * const)1184 void PluginDataElement::attribute(const int name, const char *const)
1185 #else
1186 void PluginDataElement::attribute(const int name, const char *const value)
1187 #endif
1188 {
1189 switch (name)
1190 {
1191 default:
1192 ETONYEK_DEBUG_MSG(("PluginDataElement::attribute[KEY1Parser.cpp]: unknown attribute with value=%s\n", value));
1193 }
1194 }
1195
startOfElement()1196 void PluginDataElement::startOfElement()
1197 {
1198 getState().pushIsPrototype(m_prototype);
1199 }
1200
element(const int name)1201 IWORKXMLContextPtr_t PluginDataElement::element(const int name)
1202 {
1203 switch (name)
1204 {
1205 case KEY1Token::array | KEY1Token::NS_URI_KEY : // with list of number
1206 case KEY1Token::chart_prototype | KEY1Token::NS_URI_KEY :
1207 case KEY1Token::color | KEY1Token::NS_URI_KEY :
1208 case KEY1Token::content | KEY1Token::NS_URI_KEY :
1209 case KEY1Token::dict | KEY1Token::NS_URI_KEY : // with child size, rect, ...
1210 case KEY1Token::dash_style | KEY1Token::NS_URI_KEY :
1211 case KEY1Token::fill_style | KEY1Token::NS_URI_KEY :
1212 case KEY1Token::number | KEY1Token::NS_URI_KEY :
1213 case KEY1Token::reference | KEY1Token::NS_URI_KEY : // style reference
1214 case KEY1Token::string | KEY1Token::NS_URI_KEY : // with value dictionary, root
1215 break;
1216 case KEY1Token::table | KEY1Token::NS_URI_KEY :
1217 return std::make_shared<KEY1TableElement>(getState(), m_size);
1218 default:
1219 ETONYEK_DEBUG_MSG(("PluginDataElement::element[KEY1Parser.cpp]: unknown element\n"));
1220 }
1221 return IWORKXMLContextPtr_t();
1222 }
1223
endOfElement()1224 void PluginDataElement::endOfElement()
1225 {
1226 getState().popIsPrototype();
1227 }
1228
1229 }
1230
1231 namespace
1232 {
1233
1234 class PluginElement : public BasicShapeElement
1235 {
1236 public:
1237 explicit PluginElement(KEY1ParserState &state);
1238
1239 protected:
1240 void attribute(int name, const char *value) override;
1241 IWORKXMLContextPtr_t element(int name) override;
1242 void endOfElement() override;
1243
1244 private:
1245 boost::optional<std::string> m_key;
1246 boost::optional<glm::dmat3> m_transformation;
1247 boost::optional<IWORKSize> m_size;
1248 };
1249
PluginElement(KEY1ParserState & state)1250 PluginElement::PluginElement(KEY1ParserState &state)
1251 : BasicShapeElement(state)
1252 , m_key()
1253 , m_transformation()
1254 , m_size()
1255 {
1256 }
1257
attribute(const int name,const char * const value)1258 void PluginElement::attribute(const int name, const char *const value)
1259 {
1260 switch (name)
1261 {
1262 case KEY1Token::key :
1263 m_key = value;
1264 break;
1265 case KEY1Token::transformation :
1266 m_transformation=KEY1StringConverter<glm::dmat3>::convert(value);
1267 break;
1268 default :
1269 BasicShapeElement::attribute(name,value);
1270 break;
1271 }
1272 }
1273
element(const int name)1274 IWORKXMLContextPtr_t PluginElement::element(const int name)
1275 {
1276 switch (name)
1277 {
1278 case KEY1Token::plugin_data | KEY1Token::NS_URI_KEY :
1279 return std::make_shared<PluginDataElement>(getState(), m_size, false);
1280 case KEY1Token::prototype_data | KEY1Token::NS_URI_KEY :
1281 return std::make_shared<PluginDataElement>(getState(), m_size, true);
1282 default :
1283 return BasicShapeElement::element(name);
1284 }
1285 }
1286
endOfElement()1287 void PluginElement::endOfElement()
1288 {
1289 if (!isCollector())
1290 return;
1291 IWORKStylePtr_t style=getStyle();
1292 // CHANGEME: check the plugin-data has created a table, if so, send it
1293 if (getState().m_currentTable)
1294 {
1295 getCollector().setGraphicStyle(style);
1296 if (m_transformation && m_size)
1297 {
1298 IWORKGeometryPtr_t geometry(new IWORKGeometry);
1299 glm::dvec3 pos=get(m_transformation)*glm::dvec3(0,0,1);
1300 geometry->m_position=IWORKPosition(pos[0],pos[1]);
1301 glm::dvec3 dim=get(m_transformation)*glm::dvec3(get(m_size).m_width,get(m_size).m_height,0);
1302 geometry->m_naturalSize=geometry->m_size=IWORKSize(dim[0],dim[1]);
1303 getCollector().collectGeometry(geometry);
1304 }
1305 getCollector().collectTable(getState().m_currentTable);
1306 getState().m_currentTable.reset();
1307 }
1308 }
1309
1310 }
1311
1312 namespace
1313 {
1314
1315 class GroupElement : public BasicShapeElement
1316 {
1317 public:
1318 explicit GroupElement(KEY1ParserState &state);
1319
1320 protected:
1321 void attribute(int name, const char *value) override;
1322 IWORKXMLContextPtr_t element(int name) override;
1323
1324 private:
1325 boost::optional<glm::dmat3> m_transformation;
1326 };
1327
GroupElement(KEY1ParserState & state)1328 GroupElement::GroupElement(KEY1ParserState &state)
1329 : BasicShapeElement(state)
1330 , m_transformation()
1331 {
1332 }
1333
attribute(const int name,const char * const value)1334 void GroupElement::attribute(const int name, const char *const value)
1335 {
1336 switch (name)
1337 {
1338 case KEY1Token::transformation :
1339 m_transformation=KEY1StringConverter<glm::dmat3>::convert(value);
1340 break;
1341 default :
1342 BasicShapeElement::attribute(name,value);
1343 break;
1344 }
1345 }
1346
element(const int name)1347 IWORKXMLContextPtr_t GroupElement::element(const int name)
1348 {
1349 switch (name)
1350 {
1351 case KEY1Token::g | KEY1Token::NS_URI_KEY :
1352 return std::make_shared<GroupElement>(getState());
1353 case KEY1Token::image | KEY1Token::NS_URI_KEY :
1354 return std::make_shared<ImageElement>(getState());
1355 case KEY1Token::line | KEY1Token::NS_URI_KEY :
1356 return std::make_shared<LineElement>(getState());
1357 case KEY1Token::page_number | KEY1Token::NS_URI_KEY :
1358 return std::make_shared<PageNumberElement>(getState());
1359 case KEY1Token::plugin | KEY1Token::NS_URI_KEY :
1360 return std::make_shared<PluginElement>(getState());
1361 case KEY1Token::shape | KEY1Token::NS_URI_KEY :
1362 return std::make_shared<ShapeElement>(getState());
1363 case KEY1Token::textbox | KEY1Token::NS_URI_KEY :
1364 return std::make_shared<TextboxElement>(getState());
1365 default :
1366 return BasicShapeElement::element(name);
1367 }
1368 }
1369
1370 }
1371
1372 namespace
1373 {
1374
1375 class DrawablesElement : public KEY1XMLElementContextBase
1376 {
1377 public:
1378 explicit DrawablesElement(KEY1ParserState &state, bool prototype);
1379
1380 private:
1381 void startOfElement() override;
1382 IWORKXMLContextPtr_t element(int name) override;
1383 void endOfElement() override;
1384
1385 private:
1386 bool m_prototype;
1387 };
1388
DrawablesElement(KEY1ParserState & state,bool prototype)1389 DrawablesElement::DrawablesElement(KEY1ParserState &state, bool prototype)
1390 : KEY1XMLElementContextBase(state)
1391 , m_prototype(prototype)
1392 {
1393 }
1394
startOfElement()1395 void DrawablesElement::startOfElement()
1396 {
1397 getState().pushIsPrototype(m_prototype);
1398 if (isCollector())
1399 getCollector().startLevel();
1400 }
1401
element(const int name)1402 IWORKXMLContextPtr_t DrawablesElement::element(const int name)
1403 {
1404 switch (name)
1405 {
1406 case KEY1Token::body | KEY1Token::NS_URI_KEY :
1407 return std::make_shared<BodyElement>(getState());
1408 case KEY1Token::g | KEY1Token::NS_URI_KEY :
1409 return std::make_shared<GroupElement>(getState());
1410 case KEY1Token::image | KEY1Token::NS_URI_KEY :
1411 return std::make_shared<ImageElement>(getState());
1412 case KEY1Token::line | KEY1Token::NS_URI_KEY :
1413 return std::make_shared<LineElement>(getState());
1414 case KEY1Token::page_number | KEY1Token::NS_URI_KEY :
1415 return std::make_shared<PageNumberElement>(getState());
1416 case KEY1Token::plugin | KEY1Token::NS_URI_KEY :
1417 return std::make_shared<PluginElement>(getState());
1418 case KEY1Token::shape | KEY1Token::NS_URI_KEY :
1419 return std::make_shared<ShapeElement>(getState());
1420 case KEY1Token::textbox | KEY1Token::NS_URI_KEY :
1421 return std::make_shared<TextboxElement>(getState());
1422 case KEY1Token::title | KEY1Token::NS_URI_KEY :
1423 return std::make_shared<TitleElement>(getState());
1424 default :
1425 ETONYEK_DEBUG_MSG(("DrawablesElement::element[KEY1Parser.cpp]: unknown element\n"));
1426 break;
1427 }
1428
1429 return IWORKXMLContextPtr_t();
1430 }
1431
endOfElement()1432 void DrawablesElement::endOfElement()
1433 {
1434 if (isCollector())
1435 getCollector().endLevel();
1436 getState().popIsPrototype();
1437 }
1438
1439 }
1440
1441 namespace
1442 {
1443
1444 class PluginsElement : public KEY1XMLElementContextBase
1445 {
1446 public:
1447 explicit PluginsElement(KEY1ParserState &state, bool prototype);
1448
1449 private:
1450 void startOfElement() override;
1451 IWORKXMLContextPtr_t element(int name) override;
1452 void endOfElement() override;
1453
1454 private:
1455 bool m_prototype;
1456 };
1457
PluginsElement(KEY1ParserState & state,bool prototype)1458 PluginsElement::PluginsElement(KEY1ParserState &state, bool prototype)
1459 : KEY1XMLElementContextBase(state)
1460 , m_prototype(prototype)
1461 {
1462 }
1463
startOfElement()1464 void PluginsElement::startOfElement()
1465 {
1466 getState().pushIsPrototype(m_prototype);
1467 }
1468
element(const int name)1469 IWORKXMLContextPtr_t PluginsElement::element(const int name)
1470 {
1471 switch (name)
1472 {
1473 case KEY1Token::prototype_plugin | KEY1Token::NS_URI_KEY :
1474 return std::make_shared<PluginElement>(getState());
1475 default :
1476 ETONYEK_DEBUG_MSG(("PluginsElement::element[KEY1Parser.cpp]: unknown element\n"));
1477 break;
1478 }
1479
1480 return IWORKXMLContextPtr_t();
1481 }
1482
endOfElement()1483 void PluginsElement::endOfElement()
1484 {
1485 getState().popIsPrototype();
1486 }
1487 }
1488
1489 namespace
1490 {
1491
1492 class SlideElement : public KEY1XMLElementContextBase
1493 {
1494 public:
1495 explicit SlideElement(KEY1ParserState &state, bool isMasterSlide);
1496
1497 private:
1498 void attribute(int name, const char *value) override;
1499 void startOfElement() override;
1500 IWORKXMLContextPtr_t element(int name) override;
1501 void endOfElement() override;
1502
1503 private:
1504 bool m_isMasterSlide;
1505 optional<ID_t> m_styleRef;
1506 optional<ID_t> m_masterRef;
1507
1508 boost::optional<std::string> m_name; // master name
1509 boost::optional<IWORKFill> m_background;
1510
1511 // we need to record the layer as the main style are not read
1512 std::shared_ptr<IWORKRecorder> m_recorder;
1513 boost::optional<std::string> m_notes;
1514 };
1515
SlideElement(KEY1ParserState & state,bool isMasterSlide)1516 SlideElement::SlideElement(KEY1ParserState &state, bool isMasterSlide)
1517 : KEY1XMLElementContextBase(state)
1518 , m_isMasterSlide(isMasterSlide)
1519 , m_styleRef()
1520 , m_masterRef()
1521 , m_name()
1522 , m_background()
1523 , m_recorder()
1524 , m_notes()
1525 {
1526 }
1527
1528
attribute(int name,const char * value)1529 void SlideElement::attribute(int name, const char *value)
1530 {
1531 switch (name)
1532 {
1533 case KEY1Token::name :
1534 m_name=value;
1535 break;
1536 case KEY1Token::id :
1537 setId(value);
1538 break;
1539 case KEY1Token::master_slide_id :
1540 m_masterRef=value;
1541 break;
1542 case KEY1Token::floating_content : // when exist with value=true, probably meaning has floating content
1543 break;
1544 default :
1545 ETONYEK_DEBUG_MSG(("SlideElement::attribute[KEY1Parser.cpp]: unknown attribute\n"));
1546 break;
1547 }
1548 }
1549
startOfElement()1550 void SlideElement::startOfElement()
1551 {
1552 getState().pushIsMasterSlide(m_isMasterSlide);
1553 getState().getDictionary().pushStylesContext();
1554 if (isCollector())
1555 {
1556 getCollector().startPage();
1557 getCollector().startLayer();
1558 m_recorder = std::make_shared<IWORKRecorder>();
1559 getCollector().setRecorder(m_recorder);
1560 }
1561 }
1562
element(const int name)1563 IWORKXMLContextPtr_t SlideElement::element(const int name)
1564 {
1565 switch (name)
1566 {
1567 case KEY1Token::bullets | KEY1Token::NS_URI_KEY :
1568 return std::make_shared<BulletsElement>(getState(), false);
1569 case KEY1Token::drawables | KEY1Token::NS_URI_KEY :
1570 return std::make_shared<DrawablesElement>(getState(), false);
1571 case KEY1Token::guides | KEY1Token::NS_URI_KEY : // list of guide, safe to ignore?
1572 break;
1573 case KEY1Token::notes | KEY1Token::NS_URI_KEY :
1574 return std::make_shared<CDATAElement>(getState(), m_notes);
1575 case KEY1Token::prototype_bullets | KEY1Token::NS_URI_KEY :
1576 return std::make_shared<BulletsElement>(getState(), true);
1577 case KEY1Token::prototype_drawables | KEY1Token::NS_URI_KEY :
1578 return std::make_shared<DrawablesElement>(getState(), true);
1579 case KEY1Token::prototype_plugins | KEY1Token::NS_URI_KEY :
1580 return std::make_shared<PluginsElement>(getState(), true);
1581 case KEY1Token::background_fill_style | KEY1Token::NS_URI_KEY :
1582 return std::make_shared<KEY1FillElement>(getState(), m_background);
1583 case KEY1Token::transition_style | KEY1Token::NS_URI_KEY :
1584 return std::make_shared<TransitionStyleElement>(getState());
1585 case KEY1Token::thumbnails | KEY1Token::NS_URI_KEY : // ok to ignore
1586 break;
1587 default :
1588 ETONYEK_DEBUG_MSG(("SlideElement::element[KEY1Parser.cpp]: unknown element\n"));
1589 break;
1590 }
1591
1592 return IWORKXMLContextPtr_t();
1593 }
1594
endOfElement()1595 void SlideElement::endOfElement()
1596 {
1597 getState().getDictionary().linkStylesContext(m_masterRef);
1598 if (m_isMasterSlide && getId()) getState().getDictionary().collectStylesContext(get(getId()));
1599 if (isCollector())
1600 {
1601 if (m_background)
1602 {
1603 IWORKPropertyMap props;
1604 props.put<property::Fill>(get(m_background));
1605 IWORKStylePtr_t style(new IWORKStyle(props, boost::none, boost::none));
1606
1607 getCollector().setSlideStyle(style);
1608 }
1609 if (!m_isMasterSlide)
1610 {
1611 for (int i=0; i<2; ++i)
1612 {
1613 KEYPlaceholderPtr_t placeholder=i==0 ? getState().getDictionary().getTitlePlaceholder() :
1614 getState().getDictionary().getBodyPlaceholder();
1615 if (!placeholder || (placeholder->m_visible && !get(placeholder->m_visible)))
1616 continue;
1617 getCollector().insertTextPlaceholder(placeholder);
1618 }
1619 }
1620 const KEYLayerPtr_t layer(getCollector().collectLayer());
1621 getCollector().endLayer();
1622 if (bool(layer))
1623 getCollector().insertLayer(layer);
1624 if (m_notes)
1625 {
1626 assert(!getState().m_currentText);
1627 getState().m_currentText = getCollector().createText(getState().m_langManager);
1628 getState().m_currentText->insertText(get(m_notes).c_str());
1629 getCollector().collectText(getState().m_currentText);
1630 getState().m_currentText.reset();
1631 getCollector().collectNote();
1632 }
1633 KEYSlidePtr_t slide=getCollector().collectSlide();
1634 getCollector().endPage();
1635 if (!slide)
1636 return;
1637 slide->m_name=m_name;
1638 if (m_masterRef && m_isMasterSlide)
1639 {
1640 ETONYEK_DEBUG_MSG(("SlideElement::endOfElement[KEY1Parser.cpp]: find a master slide with masterRef\n"));
1641 }
1642 else if (m_masterRef)
1643 {
1644 const KEYSlideMap_t::const_iterator it = getState().getDictionary().m_masterSlides.find(get(m_masterRef));
1645 if (it != getState().getDictionary().m_masterSlides.end())
1646 slide->m_masterSlide=it->second;
1647 else
1648 {
1649 ETONYEK_DEBUG_MSG(("SlideElement::endOfElement[KEY1Parser.cpp]: unknown master %s\n", get(m_masterRef).c_str()));
1650 }
1651 }
1652 if (!m_isMasterSlide)
1653 getState().getDictionary().m_slides.push_back(slide);
1654 else if (getId())
1655 getState().getDictionary().m_masterSlides[get(getId())]=slide;
1656 else
1657 {
1658 ETONYEK_DEBUG_MSG(("SlideElement::endOfElement[KEY1Parser.cpp]: can not find a master id\n"));
1659 }
1660 }
1661 getState().getDictionary().popStylesContext();
1662 getState().popIsMasterSlide();
1663 }
1664
1665 }
1666
1667 namespace
1668 {
1669
1670 class SlideListElement : public KEY1XMLElementContextBase
1671 {
1672 public:
1673 explicit SlideListElement(KEY1ParserState &state);
1674
1675 private:
1676 void startOfElement() override;
1677 IWORKXMLContextPtr_t element(int name) override;
1678 void endOfElement() override;
1679 };
1680
SlideListElement(KEY1ParserState & state)1681 SlideListElement::SlideListElement(KEY1ParserState &state)
1682 : KEY1XMLElementContextBase(state)
1683 {
1684 }
1685
startOfElement()1686 void SlideListElement::startOfElement()
1687 {
1688 if (isCollector())
1689 getCollector().startSlides();
1690 }
1691
element(const int name)1692 IWORKXMLContextPtr_t SlideListElement::element(const int name)
1693 {
1694 switch (name)
1695 {
1696 case KEY1Token::slide | KEY1Token::NS_URI_KEY :
1697 return std::make_shared<SlideElement>(getState(), false);
1698 default :
1699 ETONYEK_DEBUG_MSG(("SlideListElement::element[KEY1Parser.cpp]: unexpected element\n"));
1700 break;
1701 }
1702
1703 return IWORKXMLContextPtr_t();
1704 }
1705
endOfElement()1706 void SlideListElement::endOfElement()
1707 {
1708 if (isCollector())
1709 getCollector().endSlides();
1710 }
1711
1712 }
1713
1714 namespace
1715 {
1716
1717 class MasterSlidesElement : public KEY1XMLElementContextBase
1718 {
1719 public:
1720 explicit MasterSlidesElement(KEY1ParserState &state);
1721
1722 private:
1723 void startOfElement() override;
1724 IWORKXMLContextPtr_t element(int name) override;
1725 void endOfElement() override;
1726 };
1727
MasterSlidesElement(KEY1ParserState & state)1728 MasterSlidesElement::MasterSlidesElement(KEY1ParserState &state)
1729 : KEY1XMLElementContextBase(state)
1730 {
1731 }
1732
startOfElement()1733 void MasterSlidesElement::startOfElement()
1734 {
1735 if (isCollector())
1736 getCollector().startSlides();
1737 }
1738
element(const int name)1739 IWORKXMLContextPtr_t MasterSlidesElement::element(const int name)
1740 {
1741 switch (name)
1742 {
1743 case KEY1Token::master_slide | KEY1Token::NS_URI_KEY :
1744 return std::make_shared<SlideElement>(getState(), true);
1745 default :
1746 ETONYEK_DEBUG_MSG(("MasterSlidesElement::element[KEY1Parser.cpp]: unexpected element\n"));
1747 break;
1748 }
1749
1750 return IWORKXMLContextPtr_t();
1751 }
1752
endOfElement()1753 void MasterSlidesElement::endOfElement()
1754 {
1755 if (isCollector())
1756 getCollector().endSlides();
1757 }
1758 }
1759
1760 namespace
1761 {
1762 class ThemeElement : public KEY1XMLElementContextBase
1763 {
1764 public:
1765 explicit ThemeElement(KEY1ParserState &state);
1766
1767 private:
1768 void attribute(int name, const char *value) override;
1769 IWORKXMLContextPtr_t element(int name) override;
1770
1771 private:
1772 boost::optional<std::string> m_description;
1773 };
1774
ThemeElement(KEY1ParserState & state)1775 ThemeElement::ThemeElement(KEY1ParserState &state)
1776 : KEY1XMLElementContextBase(state)
1777 , m_description()
1778 {
1779 }
1780
attribute(int name,const char * value)1781 void ThemeElement::attribute(int name, const char *value)
1782 {
1783 switch (name)
1784 {
1785 case KEY1Token::slide_size :
1786 {
1787 boost::optional<IWORKSize> size=KEY1StringConverter<IWORKSize>::convert(value);
1788 if (size && isCollector())
1789 getCollector().collectPresentationSize(get(size));
1790 break;
1791 }
1792 default :
1793 ETONYEK_DEBUG_MSG(("ThemeElement::attribute[KEY1Parser.cpp]: unexpected attribute\n"));
1794 break;
1795 }
1796 }
1797
element(const int name)1798 IWORKXMLContextPtr_t ThemeElement::element(const int name)
1799 {
1800 switch (name)
1801 {
1802 case KEY1Token::description | KEY1Token::NS_URI_KEY :
1803 return std::make_shared<CDATAElement>(getState(), m_description);
1804 case KEY1Token::prototype_drawables | KEY1Token::NS_URI_KEY :
1805 return std::make_shared<DrawablesElement>(getState(), true);
1806 case KEY1Token::prototype_plugins | KEY1Token::NS_URI_KEY :
1807 return std::make_shared<PluginsElement>(getState(), true);
1808 case KEY1Token::master_slides | KEY1Token::NS_URI_KEY :
1809 return std::make_shared<MasterSlidesElement>(getState());
1810 default :
1811 ETONYEK_DEBUG_MSG(("ThemeElement::element[KEY1Parser.cpp]: unexpected element\n"));
1812 break;
1813 }
1814
1815 return IWORKXMLContextPtr_t();
1816 }
1817 }
1818
1819 namespace
1820 {
1821 class PresentationElement : public KEY1XMLElementContextBase
1822 {
1823 public:
1824 explicit PresentationElement(KEY1ParserState &state);
1825
1826 private:
1827 void attribute(int name, const char *value) override;
1828 void startOfElement() override;
1829 IWORKXMLContextPtr_t element(int name) override;
1830 void endOfElement() override;
1831
1832 private:
1833 };
1834
PresentationElement(KEY1ParserState & state)1835 PresentationElement::PresentationElement(KEY1ParserState &state)
1836 : KEY1XMLElementContextBase(state)
1837 {
1838 }
1839
startOfElement()1840 void PresentationElement::startOfElement()
1841 {
1842 if (isCollector())
1843 {
1844 getCollector().startDocument();
1845 getCollector().setAccumulateTransformTo(false);
1846 }
1847 }
1848
attribute(const int name,const char * const)1849 void PresentationElement::attribute(const int name, const char *const /*value*/)
1850 {
1851 switch (name)
1852 {
1853 case KEY1Token::version : // find 36
1854 break;
1855 default :
1856 // normally only the namespace xmlns:plugin
1857 break;
1858 }
1859 }
1860
element(const int name)1861 IWORKXMLContextPtr_t PresentationElement::element(const int name)
1862 {
1863 switch (name)
1864 {
1865 case KEY1Token::metadata | KEY1Token::NS_URI_KEY :
1866 return std::make_shared<MetadataElement>(getState());
1867 case KEY1Token::theme | KEY1Token::NS_URI_KEY :
1868 return std::make_shared<ThemeElement>(getState());
1869 case KEY1Token::slide_list | KEY1Token::NS_URI_KEY :
1870 return std::make_shared<SlideListElement>(getState());
1871 case KEY1Token::ui_state | KEY1Token::NS_URI_KEY : // safe to ignore
1872 break;
1873 default :
1874 ETONYEK_DEBUG_MSG(("PresentationElement::element[KEY1Parser.cpp]: unexpected element\n"));
1875 break;
1876 }
1877
1878 return IWORKXMLContextPtr_t();
1879 }
1880
endOfElement()1881 void PresentationElement::endOfElement()
1882 {
1883 if (isCollector())
1884 {
1885 getCollector().sendSlides(getState().getDictionary().m_slides);
1886 getCollector().endDocument();
1887 }
1888 }
1889
1890 }
1891
1892 namespace
1893 {
1894
1895 class XMLDocument : public KEY1XMLElementContextBase
1896 {
1897 public:
1898 explicit XMLDocument(KEY1ParserState &state);
1899
1900 private:
1901 IWORKXMLContextPtr_t element(int name) override;
1902 };
1903
XMLDocument(KEY1ParserState & state)1904 XMLDocument::XMLDocument(KEY1ParserState &state)
1905 : KEY1XMLElementContextBase(state)
1906 {
1907 }
1908
element(const int name)1909 IWORKXMLContextPtr_t XMLDocument::element(const int name)
1910 {
1911 switch (name)
1912 {
1913 case KEY1Token::presentation | KEY1Token::NS_URI_KEY :
1914 return std::make_shared<PresentationElement>(m_state);
1915 default:
1916 ETONYEK_DEBUG_MSG(("XMLDocument::element[KEY1Parser.cpp]: unexpected element\n"));
1917 break;
1918 }
1919
1920 return IWORKXMLContextPtr_t();
1921 }
1922
1923 }
1924
1925 namespace
1926 {
1927
1928 class DiscardContext : public KEY1XMLContextBase<IWORKDiscardContext>
1929 {
1930 public:
1931 explicit DiscardContext(KEY1ParserState &state);
1932 ~DiscardContext();
1933
1934 private:
1935 IWORKXMLContextPtr_t element(int name) override;
1936
1937 };
1938
DiscardContext(KEY1ParserState & state)1939 DiscardContext::DiscardContext(KEY1ParserState &state)
1940 : KEY1XMLContextBase<IWORKDiscardContext>(state)
1941 {
1942 }
1943
~DiscardContext()1944 DiscardContext::~DiscardContext()
1945 {
1946 }
1947
element(const int name)1948 IWORKXMLContextPtr_t DiscardContext::element(const int name)
1949 {
1950 return KEY1XMLContextBase<IWORKDiscardContext>::element(name);
1951 }
1952
1953 }
1954
KEY1Parser(const RVNGInputStreamPtr_t & input,const RVNGInputStreamPtr_t & package,KEYCollector & collector,KEY1Dictionary & dict)1955 KEY1Parser::KEY1Parser(const RVNGInputStreamPtr_t &input, const RVNGInputStreamPtr_t &package, KEYCollector &collector, KEY1Dictionary &dict)
1956 : IWORKParser(input, package)
1957 , m_state(*this, collector, dict)
1958 , m_data()
1959 {
1960
1961 }
1962
~KEY1Parser()1963 KEY1Parser::~KEY1Parser()
1964 {
1965 }
1966
createDocumentContext()1967 IWORKXMLContextPtr_t KEY1Parser::createDocumentContext()
1968 {
1969 return std::make_shared<XMLDocument>(m_state);
1970 }
1971
createDiscardContext()1972 IWORKXMLContextPtr_t KEY1Parser::createDiscardContext()
1973 {
1974 return std::make_shared<DiscardContext>(m_state);
1975 }
1976
getTokenizer() const1977 const IWORKTokenizer &KEY1Parser::getTokenizer() const
1978 {
1979 return KEY1Token::getTokenizer();
1980 }
1981
1982 }
1983
1984 /* vim:set shiftwidth=2 softtabstop=2 expandtab: */
1985