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