1 /*
2  * This file is part of Office 2007 Filters for Calligra
3  *
4  * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
5  *
6  * Contact: Suresh Chande suresh.chande@nokia.com
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * version 2.1 as published by the Free Software Foundation.
11  *
12  * This library is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  *
22  */
23 
24 #include "PptxXmlDocumentReader.h"
25 
26 #include "PptxXmlCommentAuthorsReader.h"
27 #include "PptxImport.h"
28 #include "PptxDebug.h"
29 
30 #include <VmlDrawingReader.h>
31 #include <MsooXmlRelationships.h>
32 #include <MsooXmlSchemas.h>
33 #include <MsooXmlUtils.h>
34 #include <MsooXmlUnits.h>
35 #include <MsooXmlDrawingTableStyleReader.h>
36 
37 #include <KoXmlWriter.h>
38 #include <KoGenStyles.h>
39 #include <KoPageLayout.h>
40 #include <KoOdfGraphicStyles.h>
41 
42 #include <KoTable.h>
43 #include <KoRow.h>
44 #include <KoColumn.h>
45 #include <KoCell.h>
46 #include <KoCellStyle.h>
47 
48 #define MSOOXML_CURRENT_NS "p"
49 #define MSOOXML_CURRENT_CLASS PptxXmlDocumentReader
50 #define BIND_READ_CLASS MSOOXML_CURRENT_CLASS
51 #define PPTXXMLDOCUMENTREADER_CPP
52 
53 #include <MsooXmlReader_p.h>
54 
55 
PptxXmlDocumentReaderContext(PptxImport & _import,const QString & _path,const QString & _file,MSOOXML::MsooXmlRelationships & _relationships)56 PptxXmlDocumentReaderContext::PptxXmlDocumentReaderContext(
57     PptxImport& _import, const QString& _path, const QString& _file,
58     MSOOXML::MsooXmlRelationships& _relationships)
59         : import(&_import),
60           path(_path), file(_file), relationships(&_relationships)
61 {
62     firstReadRound = true;
63     numberOfItems = 0;
64 }
65 
66 class PptxXmlDocumentReader::Private
67 {
68 public:
Private()69     Private()
70     {
71     }
~Private()72     ~Private() {
73         qDeleteAll(slideLayoutPropertiesMap);
74     }
75     QMap<QString, PptxSlideProperties*> slideLayoutPropertiesMap;
76     uint slideNumber; //!< temp., see todo in PptxXmlDocumentReader::read_sldId()
77     bool sldSzRead, noteSzRead;
78     KoPageLayout pageLayout, notePageLayout;
79 
80     // Several because there are several masterpages
81     QVector<QString> masterPageDrawStyleNames;
82     QVector<KoGenStyle> masterPageStyles;
83     QVector<QString> masterPageFrames;
84 
85     QMap<QString, PptxSlideProperties> slideMasterPageProperties;
86     QMap<QString, PptxSlideProperties> notesMasterPageProperties;
87 
88     QMap<int, QString> commentAuthors;
89 private:
90 };
91 
PptxXmlDocumentReader(KoOdfWriters * writers)92 PptxXmlDocumentReader::PptxXmlDocumentReader(KoOdfWriters *writers)
93         : MSOOXML::MsooXmlCommonReader(writers)
94         , m_writers(writers)
95         , m_context(0)
96         , d(new Private)
97 {
98     init();
99 }
100 
~PptxXmlDocumentReader()101 PptxXmlDocumentReader::~PptxXmlDocumentReader()
102 {
103     delete d;
104 }
105 
init()106 void PptxXmlDocumentReader::init()
107 {
108     m_defaultNamespace = QLatin1String(MSOOXML_CURRENT_NS ":");
109 }
110 
read(MSOOXML::MsooXmlReaderContext * context)111 KoFilter::ConversionStatus PptxXmlDocumentReader::read(MSOOXML::MsooXmlReaderContext* context)
112 {
113     m_context = dynamic_cast<PptxXmlDocumentReaderContext*>(context);
114     Q_ASSERT(m_context);
115     d->slideNumber = 0;
116     d->sldSzRead = false;
117     d->noteSzRead = false;
118     d->pageLayout = KoPageLayout();
119     d->notePageLayout = KoPageLayout();
120 
121     const KoFilter::ConversionStatus result = readInternal();
122 
123     m_context = 0;
124     return result;
125 }
126 
readInternal()127 KoFilter::ConversionStatus PptxXmlDocumentReader::readInternal()
128 {
129     debugPptx << "=============================";
130     readNext();
131     if (!isStartDocument()) {
132         return KoFilter::WrongFormat;
133     }
134 
135     // p:presentation
136     readNext();
137     debugPptx << *this << namespaceUri();
138 
139     if (!expectEl("p:presentation")) {
140         return KoFilter::WrongFormat;
141     }
142     if (!expectNS(MSOOXML::Schemas::presentationml)) {
143         return KoFilter::WrongFormat;
144     }
145 //     const QXmlStreamAttributes attrs( attributes() );
146 //     for (int i=0; i<attrs.count(); i++) {
147 //         debugPptx << "1 NS prefix:" << attrs[i].name() << "uri:" << attrs[i].namespaceUri();
148 
149     QXmlStreamNamespaceDeclarations namespaces(namespaceDeclarations());
150     for (int i = 0; i < namespaces.count(); i++) {
151         debugPptx << "NS prefix:" << namespaces[i].prefix() << "uri:" << namespaces[i].namespaceUri();
152     }
153 //! @todo find out whether the namespace returned by namespaceUri()
154 //!       is exactly the same ref as the element of namespaceDeclarations()
155     if (!namespaces.contains(QXmlStreamNamespaceDeclaration("p", MSOOXML::Schemas::presentationml))) {
156         raiseError(i18n("Namespace \"%1\" not found", QLatin1String(MSOOXML::Schemas::presentationml)));
157         return KoFilter::WrongFormat;
158     }
159 //! @todo expect other namespaces too...
160 
161     {
162         PptxXmlCommentAuthorsReader autorsReader(this);
163         const QString autorsFilePath = m_context->relationships->targetForType(m_context->path, m_context->file, MSOOXML::Relationships::commentAuthors);
164         PptxXmlCommentAuthorsReaderContext autorsContext;
165         m_context->import->loadAndParseDocument(&autorsReader, autorsFilePath, &autorsContext);
166         d->commentAuthors = autorsContext.authors;
167     }
168 
169     TRY_READ(presentation)
170     debugPptx << "===========finished============";
171     return KoFilter::OK;
172 }
173 
slideLayoutProperties(const QString & slidePath,const QString & slideFile)174 PptxSlideProperties* PptxXmlDocumentReader::slideLayoutProperties(const QString& slidePath, const QString& slideFile)
175 {
176     const QString slideLayoutPathAndFile(m_context->relationships->targetForType(
177         slidePath, slideFile,
178         QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideLayout"));
179     debugPptx << QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideLayout";
180     debugPptx << "slideLayoutPathAndFile:" << slideLayoutPathAndFile;
181     if (slideLayoutPathAndFile.isEmpty())
182         return 0;
183 
184     QString slideLayoutPath, slideLayoutFile;
185     MSOOXML::Utils::splitPathAndFile(slideLayoutPathAndFile, &slideLayoutPath, &slideLayoutFile);
186 
187     // load layout or find in cache
188     PptxSlideProperties *result = d->slideLayoutPropertiesMap.value(slideLayoutPathAndFile);
189     if (result)
190         return result;
191 
192     QString slideMasterPath, slideMasterFile;
193     MSOOXML::Utils::splitPathAndFile(m_context->relationships->targetForType(slidePath, slideFile,
194         QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideLayout"), &slideMasterPath, &slideMasterFile);
195     const QString slideMasterPathAndFile = m_context->relationships->targetForType(slideMasterPath, slideMasterFile,
196          QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideMaster");
197 
198     result = new PptxSlideProperties();
199     result->m_slideMasterName = slideMasterPathAndFile;
200 
201     VmlDrawingReader vmlreader(this);
202     QString vmlTarget = m_context->relationships->targetForType(slideLayoutPath, slideLayoutFile,
203         "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing");
204 
205     if (!vmlTarget.isEmpty()) {
206         QString errorMessage, vmlPath, vmlFile;
207 
208         QString fileName = vmlTarget;
209         fileName.remove(0, m_context->path.length());
210         MSOOXML::Utils::splitPathAndFile(vmlTarget, &vmlPath, &vmlFile);
211 
212         VmlDrawingReaderContext vmlContext(*m_context->import,
213             vmlPath, vmlFile, *m_context->relationships);
214 
215         const KoFilter::ConversionStatus status =
216             m_context->import->loadAndParseDocument(&vmlreader, vmlTarget, errorMessage, &vmlContext);
217         if (status != KoFilter::OK) {
218             vmlreader.raiseError(errorMessage);
219         }
220     }
221 
222     MSOOXML::Utils::AutoPtrSetter<PptxSlideProperties> slideLayoutPropertiesSetter(result);
223     PptxXmlSlideReaderContext context(
224         *m_context->import,
225         slideLayoutPath, slideLayoutFile,
226         0/*unused*/, &d->slideMasterPageProperties[slideMasterPathAndFile].theme,
227         PptxXmlSlideReader::SlideLayout,
228         result,
229         &d->slideMasterPageProperties[slideMasterPathAndFile], //PptxSlideMasterPageProperties
230         0,
231         *m_context->relationships,
232         d->commentAuthors,
233         d->slideMasterPageProperties[slideMasterPathAndFile].colorMap,
234         vmlreader
235     );
236 
237     PptxXmlSlideReader slideLayoutReader(this);
238     context.firstReadingRound = true;
239 
240     KoFilter::ConversionStatus status = m_context->import->loadAndParseDocument(
241         &slideLayoutReader, slideLayoutPath + '/' + slideLayoutFile, &context);
242     if (status != KoFilter::OK) {
243         debugPptx << slideLayoutReader.errorString();
244         return 0;
245     }
246 
247     context.initializeContext(d->slideMasterPageProperties[slideMasterPathAndFile].theme, defaultParagraphStyles,
248         defaultTextStyles, defaultListStyles, defaultBulletColors, defaultTextColors, defaultLatinFonts);
249 
250     context.firstReadingRound = false;
251     status = m_context->import->loadAndParseDocument(
252         &slideLayoutReader, slideLayoutPath + '/' + slideLayoutFile, &context);
253     if (status != KoFilter::OK) {
254         debugPptx << slideLayoutReader.errorString();
255         return 0;
256     }
257 
258     slideLayoutPropertiesSetter.release();
259     d->slideLayoutPropertiesMap.insert(slideLayoutPathAndFile, result);
260     return result;
261 }
262 
263 #undef CURRENT_EL
264 #define CURRENT_EL sldId
265 //! p:sldId handler (Slide ID)
266 /*! ECMA-376, 19.2.1.33, p. 2797.
267 
268   This element specifies a presentation slide that is available within the
269   corresponding presentation.
270 
271   Parent elements:
272   - [done] sldIdLst (§19.2.1.34)
273 
274   Child elements:
275   - extLst (Extension List)
276 */
read_sldId()277 KoFilter::ConversionStatus PptxXmlDocumentReader::read_sldId()
278 {
279     READ_PROLOGUE
280     const QXmlStreamAttributes attrs(attributes());
281     TRY_READ_ATTR_WITHOUT_NS(id)
282     READ_ATTR_WITH_NS(r, id)
283     debugPptx << "id:" << id << "r:id:" << r_id;
284 
285     // locate this slide
286     const QString slidePathAndFile(m_context->relationships->target(m_context->path, m_context->file, r_id));
287     debugPptx << "slidePathAndFile:" << slidePathAndFile;
288 
289     QString slidePath, slideFile;
290     MSOOXML::Utils::splitPathAndFile(slidePathAndFile, &slidePath, &slideFile);
291 
292     PptxSlideProperties *slideLayoutProperties = this->slideLayoutProperties(slidePath, slideFile);
293     if (!slideLayoutProperties) {
294         raiseError(i18n("Slide layout \"%1\" not found", slidePath + '/' + slideFile));
295         return KoFilter::WrongFormat;
296     }
297 
298     VmlDrawingReader vmlreader(this);
299     QString vmlTarget = m_context->relationships->targetForType(slidePath, slideFile,
300         "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing");
301 
302     if (!vmlTarget.isEmpty()) {
303         QString errorMessage, vmlPath, vmlFile;
304 
305         QString fileName = vmlTarget;
306         fileName.remove(0, m_context->path.length());
307         MSOOXML::Utils::splitPathAndFile(vmlTarget, &vmlPath, &vmlFile);
308 
309         VmlDrawingReaderContext vmlContext(*m_context->import,
310             vmlPath, vmlFile, *m_context->relationships);
311 
312         const KoFilter::ConversionStatus status =
313             m_context->import->loadAndParseDocument(&vmlreader, vmlTarget, errorMessage, &vmlContext);
314         if (status != KoFilter::OK) {
315             vmlreader.raiseError(errorMessage);
316         }
317     }
318 
319     QString slideMasterPath, slideMasterFile;
320     MSOOXML::Utils::splitPathAndFile(m_context->relationships->targetForType(slidePath, slideFile, QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideLayout"), &slideMasterPath, &slideMasterFile);
321     const QString slideMasterPathAndFile = m_context->relationships->targetForType(slideMasterPath, slideMasterFile, QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideMaster");
322 
323     // Delay the reading of a tableStyle until we find a table as we need the
324     // clrMap from the master slide
325     const QString tableStylesFilePath = m_context->relationships->targetForType(m_context->path, m_context->file, MSOOXML::Relationships::tableStyles);
326 
327     PptxSlideProperties *notes = 0;
328     const QString notesTarget(m_context->relationships->targetForType(m_context->path, m_context->file,
329         "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster"));
330     if (!notesTarget.isEmpty()) {
331         notes = &d->notesMasterPageProperties[notesTarget];
332     }
333 
334     PptxXmlSlideReaderContext context(
335         *m_context->import,
336         slidePath, slideFile,
337         d->slideNumber,
338         &d->slideMasterPageProperties[slideLayoutProperties->m_slideMasterName].theme,
339         PptxXmlSlideReader::Slide,
340         slideLayoutProperties,
341         &d->slideMasterPageProperties[slideLayoutProperties->m_slideMasterName],
342         notes,
343         *m_context->relationships,
344         d->commentAuthors,
345         d->slideMasterPageProperties[slideLayoutProperties->m_slideMasterName].colorMap,
346         vmlreader,
347         tableStylesFilePath
348     );
349 
350     // 1st reading round - read possible colorMap override
351     PptxXmlSlideReader slideReader(this);
352     context.firstReadingRound = true;
353 
354     KoFilter::ConversionStatus status = m_context->import->loadAndParseDocument(
355         &slideReader, slidePath + '/' + slideFile, &context);
356     if (status != KoFilter::OK) {
357         debugPptx << slideReader.errorString();
358         return status;
359     }
360 
361     context.initializeContext(d->slideMasterPageProperties[slideLayoutProperties->m_slideMasterName].theme, defaultParagraphStyles,
362         defaultTextStyles, defaultListStyles, defaultBulletColors, defaultTextColors, defaultLatinFonts);
363 
364     // 2nd reading round
365     context.firstReadingRound = false;
366     status = m_context->import->loadAndParseDocument(&slideReader, slidePath + '/' + slideFile, &context);
367     if (status != KoFilter::OK) {
368         debugPptx << slideReader.errorString();
369         return status;
370     }
371 
372     ++d->slideNumber;
373 
374     SKIP_EVERYTHING
375     READ_EPILOGUE
376 }
377 
378 #undef CURRENT_EL
379 #define CURRENT_EL notesMasterId
380 //! p:noteMasterId (Note Master ID)
381 /*!
382  Parent elements:
383     - [done] noteMasterIdLst (§19.2.1.37)
384 
385  Child elements:
386     - extLst (Extension List) §19.2.1.12
387 */
read_notesMasterId()388 KoFilter::ConversionStatus PptxXmlDocumentReader::read_notesMasterId()
389 {
390     READ_PROLOGUE
391     const QXmlStreamAttributes attrs(attributes());
392     READ_ATTR_WITH_NS(r, id)
393 
394     const QString notesMasterPathAndFile(m_context->relationships->target(m_context->path, m_context->file, r_id));
395     debugPptx << "notesMasterPathAndFile:" << notesMasterPathAndFile;
396 
397     QString notesMasterPath, notesMasterFile;
398     MSOOXML::Utils::splitPathAndFile(notesMasterPathAndFile, &notesMasterPath, &notesMasterFile);
399 
400     // Reading the notesmaster theme
401     PptxSlideProperties notesPageProperties;
402 
403     const QString notesThemePathAndFile(m_context->relationships->targetForType(
404         notesMasterPath, notesMasterFile,
405         QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/theme"));
406     debugPptx << QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/theme";
407     debugPptx << "notesThemePathAndFile:" << notesThemePathAndFile;
408 
409     QString notesThemePath, notesThemeFile;
410     MSOOXML::Utils::splitPathAndFile(notesThemePathAndFile, &notesThemePath, &notesThemeFile);
411 
412     MSOOXML::MsooXmlThemesReader themesReader(m_writers);
413     MSOOXML::MsooXmlThemesReaderContext themecontext(notesPageProperties.theme, m_context->relationships, m_context->import,
414         notesThemePath, notesThemeFile);
415 
416     QString errorMessage;
417 
418     KoFilter::ConversionStatus status
419         = m_context->import->loadAndParseDocument(&themesReader, notesThemePathAndFile, errorMessage, &themecontext);
420 
421     //empty map used here as slideMaster is the place where the map is created
422     QMap<QString, QString> dummyMap;
423 
424     VmlDrawingReader vmlreader(this);
425     QString vmlTarget = m_context->relationships->targetForType(notesMasterPath, notesMasterFile,
426         "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing");
427 
428     if (!vmlTarget.isEmpty()) {
429         QString errorMessage, vmlPath, vmlFile;
430 
431         QString fileName = vmlTarget;
432         fileName.remove(0, m_context->path.length());
433         MSOOXML::Utils::splitPathAndFile(vmlTarget, &vmlPath, &vmlFile);
434 
435         VmlDrawingReaderContext vmlContext(*m_context->import,
436             vmlPath, vmlFile, *m_context->relationships);
437 
438         const KoFilter::ConversionStatus status =
439             m_context->import->loadAndParseDocument(&vmlreader, vmlTarget, errorMessage, &vmlContext);
440         if (status != KoFilter::OK) {
441             vmlreader.raiseError(errorMessage);
442         }
443     }
444 
445     PptxXmlSlideReaderContext context(
446         *m_context->import,
447         notesMasterPath, notesMasterFile,
448         0, &notesPageProperties.theme,
449         PptxXmlSlideReader::NotesMaster,
450         0,
451         0,
452         &notesPageProperties,
453         *m_context->relationships,
454         d->commentAuthors,
455         dummyMap,
456         vmlreader,
457         QString()
458     );
459 
460     PptxXmlSlideReader notesMasterReader(this);
461     context.firstReadingRound = true;
462     status = m_context->import->loadAndParseDocument(
463         &notesMasterReader, notesMasterPath + '/' + notesMasterFile, &context);
464     if (status != KoFilter::OK) {
465         debugPptx << notesMasterReader.errorString();
466         return status;
467     }
468 
469     context.initializeContext(notesPageProperties.theme, defaultParagraphStyles,
470         defaultTextStyles, defaultListStyles, defaultBulletColors, defaultTextColors, defaultLatinFonts);
471 
472     // In this context we already have the real colorMap
473     context.firstReadingRound = false;
474 
475     status = m_context->import->loadAndParseDocument(
476         &notesMasterReader, notesMasterPath + '/' + notesMasterFile, &context);
477     if (status != KoFilter::OK) {
478         debugPptx << notesMasterReader.errorString();
479         return status;
480     }
481 
482     d->notesMasterPageProperties.insert(notesMasterPathAndFile, notesPageProperties);
483 
484     SKIP_EVERYTHING
485     READ_EPILOGUE
486 }
487 
488 #undef CURRENT_EL
489 #define CURRENT_EL sldMasterId
490 //! p:sldMasterId (Slide Master ID)
491 /*! This element specifies a slide master that is available within the corresponding presentation.
492     A slide master is a slide that is specifically designed to be a template for all related child layout slides.
493 
494  ECMA-376, 19.2.1.33, p. 2797.
495  Parent elements:
496     - [done] sldMasterIdLst (§19.2.1.37)
497  Child elements:
498     - extLst (Extension List) §19.2.1.12
499 */
read_sldMasterId()500 KoFilter::ConversionStatus PptxXmlDocumentReader::read_sldMasterId()
501 {
502     READ_PROLOGUE
503     const QXmlStreamAttributes attrs(attributes());
504     TRY_READ_ATTR_WITHOUT_NS(id)
505     READ_ATTR_WITH_NS(r, id)
506     debugPptx << "id:" << id << "r:id:" << r_id;
507 
508     const QString slideMasterPathAndFile(m_context->relationships->target(m_context->path, m_context->file, r_id));
509     debugPptx << "slideMasterPathAndFile:" << slideMasterPathAndFile;
510 
511     QString slideMasterPath, slideMasterFile;
512     MSOOXML::Utils::splitPathAndFile(slideMasterPathAndFile, &slideMasterPath, &slideMasterFile);
513 
514     // Reading the slidemaster theme
515 
516     PptxSlideProperties masterPageProperties;
517 
518     const QString slideThemePathAndFile(m_context->relationships->targetForType(
519         slideMasterPath, slideMasterFile,
520         QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/theme"));
521     debugPptx << QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/theme";
522     debugPptx << "slideThemePathAndFile:" << slideThemePathAndFile;
523 
524     QString slideThemePath, slideThemeFile;
525     MSOOXML::Utils::splitPathAndFile(slideThemePathAndFile, &slideThemePath, &slideThemeFile);
526 
527     MSOOXML::MsooXmlThemesReader themesReader(m_writers);
528     MSOOXML::MsooXmlThemesReaderContext themecontext(masterPageProperties.theme, m_context->relationships, m_context->import,
529         slideThemePath, slideThemeFile);
530 
531     QString errorMessage;
532 
533     KoFilter::ConversionStatus status
534         = m_context->import->loadAndParseDocument(&themesReader, slideThemePathAndFile, errorMessage, &themecontext);
535 
536     //empty map used here as slideMaster is the place where the map is created
537     QMap<QString, QString> dummyMap;
538 
539     VmlDrawingReader vmlreader(this);
540     QString vmlTarget = m_context->relationships->targetForType(slideMasterPath, slideMasterFile,
541         "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing");
542 
543     if (!vmlTarget.isEmpty()) {
544         QString errorMessage, vmlPath, vmlFile;
545 
546         QString fileName = vmlTarget;
547         fileName.remove(0, m_context->path.length());
548         MSOOXML::Utils::splitPathAndFile(vmlTarget, &vmlPath, &vmlFile);
549 
550         VmlDrawingReaderContext vmlContext(*m_context->import,
551             vmlPath, vmlFile, *m_context->relationships);
552 
553         const KoFilter::ConversionStatus status =
554             m_context->import->loadAndParseDocument(&vmlreader, vmlTarget, errorMessage, &vmlContext);
555         if (status != KoFilter::OK) {
556             vmlreader.raiseError(errorMessage);
557         }
558     }
559 
560     PptxXmlSlideReaderContext context(
561         *m_context->import,
562         slideMasterPath, slideMasterFile,
563         0/*unused*/, &masterPageProperties.theme,
564         PptxXmlSlideReader::SlideMaster,
565         0,
566         &masterPageProperties,
567         0,
568         *m_context->relationships,
569         d->commentAuthors,
570         dummyMap,
571         vmlreader,
572         QString()
573     );
574 
575     PptxXmlSlideReader slideMasterReader(this);
576     context.firstReadingRound = true;
577     status = m_context->import->loadAndParseDocument(
578         &slideMasterReader, slideMasterPath + '/' + slideMasterFile, &context);
579     if (status != KoFilter::OK) {
580         debugPptx << slideMasterReader.errorString();
581         return status;
582     }
583 
584     context.initializeContext(masterPageProperties.theme, defaultParagraphStyles,
585         defaultTextStyles, defaultListStyles, defaultBulletColors, defaultTextColors, defaultLatinFonts);
586 
587     // In this context we already have the real colorMap
588     context.firstReadingRound = false;
589 
590     status = m_context->import->loadAndParseDocument(
591         &slideMasterReader, slideMasterPath + '/' + slideMasterFile, &context);
592     if (status != KoFilter::OK) {
593         debugPptx << slideMasterReader.errorString();
594         return status;
595     }
596 
597     d->slideMasterPageProperties.insert(slideMasterPathAndFile, masterPageProperties);
598     d->masterPageDrawStyleNames.push_back(context.pageDrawStyleName);
599     d->masterPageFrames += context.pageFrames;
600     debugPptx << "d->masterPageDrawStyleName:" << d->masterPageDrawStyleNames.back();
601     SKIP_EVERYTHING
602     READ_EPILOGUE
603 }
604 
605 #undef CURRENT_EL
606 #define CURRENT_EL sldIdLst
607 //! p:sldIdLst handler (List of Slide IDs)
608 /*! ECMA-376, 19.2.1.34, p. 2798.
609  Parent elements:
610     - [done] presentation (§19.2.1.26)
611  Child elements:
612     - [done] sldId (Slide ID)
613 */
read_sldIdLst()614 KoFilter::ConversionStatus PptxXmlDocumentReader::read_sldIdLst()
615 {
616     READ_PROLOGUE
617     while (!atEnd()) {
618         readNext();
619         debugPptx << *this;
620         BREAK_IF_END_OF(CURRENT_EL)
621         if (isStartElement()) {
622             if (name() == "sldId") {
623                 TRY_READ(sldId)
624                 if (m_context->numberOfItems > 0) {
625                     m_context->import->reportProgress(100 / m_context->numberOfItems);
626                     m_context->numberOfItems = m_context->numberOfItems - 1;
627                 }
628             }
629             ELSE_WRONG_FORMAT
630         }
631     }
632     READ_EPILOGUE
633 }
634 
635 #undef CURRENT_EL
636 #define CURRENT_EL notesMasterIdLst
637 //! p:noteMasterIdLst handler (List of Note Master IDs)
638 /*!
639 
640  Parent elements:
641  - [done] presentation (§19.2.1.26)
642 
643  Child elements:
644  - [done] noteMasterId (Note Master ID) §19.2.1.36
645 */
read_notesMasterIdLst()646 KoFilter::ConversionStatus PptxXmlDocumentReader::read_notesMasterIdLst()
647 {
648     READ_PROLOGUE
649     while (!atEnd()) {
650         readNext();
651         BREAK_IF_END_OF(CURRENT_EL)
652         if (isStartElement()) {
653             if (name() == "notesMasterId") {
654                 TRY_READ(notesMasterId)
655                 if (m_context->numberOfItems > 0) {
656                     m_context->import->reportProgress(100 / m_context->numberOfItems);
657                     m_context->numberOfItems = m_context->numberOfItems - 1;
658                 }
659             }
660             ELSE_WRONG_FORMAT
661         }
662     }
663 
664     READ_EPILOGUE
665 }
666 
667 #undef CURRENT_EL
668 #define CURRENT_EL sldMasterIdLst
669 //! p:sldMasterIdLst handler (List of Slide Master IDs)
670 /*! ECMA-376, 19.2.1.37, p. 2800
671  This element specifies a list of identification information for the slide master slides that
672  are available within the corresponding presentation. A slide master is a slide that
673  is specifically designed to be a template for all related child layout slides.
674 
675  Parent elements:
676  - [done] presentation (§19.2.1.26)
677  Child elements:
678  - [done] sldMasterId (Slide Master ID) §19.2.1.36
679 */
read_sldMasterIdLst()680 KoFilter::ConversionStatus PptxXmlDocumentReader::read_sldMasterIdLst()
681 {
682     READ_PROLOGUE
683     while (!atEnd()) {
684         readNext();
685         BREAK_IF_END_OF(CURRENT_EL)
686         if (isStartElement()) {
687             if (name() == "sldMasterId") {
688                 TRY_READ(sldMasterId)
689                 if (m_context->numberOfItems > 0) {
690                     m_context->import->reportProgress(100 / m_context->numberOfItems);
691                     m_context->numberOfItems = m_context->numberOfItems - 1;
692                 }
693             }
694             ELSE_WRONG_FORMAT
695         }
696     }
697 
698     READ_EPILOGUE
699 }
700 
701 #undef CURRENT_EL
702 #define CURRENT_EL notesSz
703 //! p:noteSz handler
704 /*!
705 
706  Parent elements:
707  - [done] presentation (§19.2.1.26)
708 
709  No child elements.
710 */
read_notesSz()711 KoFilter::ConversionStatus PptxXmlDocumentReader::read_notesSz()
712 {
713     READ_PROLOGUE
714     const QXmlStreamAttributes attrs(attributes());
715     READ_ATTR_WITHOUT_NS(cx)
716     READ_ATTR_WITHOUT_NS(cy)
717     int intCx = 0;
718     int intCy = 0;
719     STRING_TO_INT(cx, intCx, "notesSz@cx")
720     STRING_TO_INT(cy, intCy, "notesSz@cy")
721     //! @todo check "type" attr, e.g. 4x3
722 
723     d->notePageLayout.width = EMU_TO_POINT(qreal(intCx));
724     d->notePageLayout.height = EMU_TO_POINT(qreal(intCy));
725     d->notePageLayout.leftMargin = 0.0;
726     d->notePageLayout.rightMargin = 0.0;
727     d->notePageLayout.topMargin = 0.0;
728     d->notePageLayout.bottomMargin = 0.0;
729 
730     d->notePageLayout.orientation = d->notePageLayout.width > d->notePageLayout.height
731         ? KoPageFormat::Landscape : KoPageFormat::Portrait;
732 
733     readNext();
734 
735     d->noteSzRead = true;
736     READ_EPILOGUE
737 }
738 
739 #undef CURRENT_EL
740 #define CURRENT_EL sldSz
741 //! p:sldSz handler (Presentation)
742 /*! ECMA-376, 19.2.1.39, p. 2801.
743  This element specifies the size of the presentation slide surface.
744 
745  Parent elements:
746  - [done] presentation (§19.2.1.26)
747 
748  No child elements.
749 */
read_sldSz()750 KoFilter::ConversionStatus PptxXmlDocumentReader::read_sldSz()
751 {
752     READ_PROLOGUE
753     const QXmlStreamAttributes attrs(attributes());
754     READ_ATTR_WITHOUT_NS(cx)
755     READ_ATTR_WITHOUT_NS(cy)
756     int intCx = 0;
757     int intCy = 0;
758     STRING_TO_INT(cx, intCx, "sldSz@cx")
759     STRING_TO_INT(cy, intCy, "sldSz@cy")
760     //! @todo check "type" attr, e.g. 4x3
761 
762     d->pageLayout.width = EMU_TO_POINT(qreal(intCx));
763     d->pageLayout.height = EMU_TO_POINT(qreal(intCy));
764     d->pageLayout.leftMargin = 0.0;
765     d->pageLayout.rightMargin = 0.0;
766     d->pageLayout.topMargin = 0.0;
767     d->pageLayout.bottomMargin = 0.0;
768     //! @todo orientation heuristics - OK?
769     d->pageLayout.orientation = d->pageLayout.width > d->pageLayout.height
770         ? KoPageFormat::Landscape : KoPageFormat::Portrait;
771 
772     readNext();
773 
774     d->sldSzRead = true;
775     READ_EPILOGUE
776 }
777 
778 //! defaultTextStyle (Presentation Default Text Style)
779 /*! ECMA-376, 19.2.1.8, p. 2773.
780 
781  This element specifies the default text styles that are to be used within the
782  presentation.  The text style defined here can be referenced when inserting a
783  new slide if that slide is not associated with a master slide or if no styling
784  information has been otherwise specified for the text within the presentation
785  slide.
786 
787  Parent element:
788  - [done] presentation (§19.2.1.26)
789 
790  Child elements:
791  - defPPr (§21.1.2.2.2)
792  - extLst (§20.1.2.2.15)
793  - [done] lvl1pPr (§21.1.2.4.13)
794  - [done] lvl2pPr (§21.1.2.4.14)
795  - [done] lvl3pPr (§21.1.2.4.15)
796  - [done] lvl4pPr (§21.1.2.4.16)
797  - [done] lvl5pPr (§21.1.2.4.17)
798  - [done] lvl6pPr (§21.1.2.4.18)
799  - [done] lvl7pPr (§21.1.2.4.19)
800  - [done] lvl8pPr (§21.1.2.4.20)
801  - [done] lvl9pPr (§21.1.2.4.21)
802 */
803 #undef CURRENT_EL
804 #define CURRENT_EL defaultTextStyle
read_defaultTextStyle()805 KoFilter::ConversionStatus PptxXmlDocumentReader::read_defaultTextStyle()
806 {
807     READ_PROLOGUE
808     m_currentListStyle = KoGenStyle(KoGenStyle::ListStyle);
809 
810     while (!atEnd()) {
811         readNext();
812         debugPptx << *this;
813         BREAK_IF_END_OF(CURRENT_EL)
814         if (isStartElement()) {
815             // Initializing the default style for the level.  At the end, there
816             // should be 9 levels
817             if (qualifiedName().toString().startsWith(QLatin1String("a:lvl"))) {
818                 defaultTextColors.push_back(QString());
819                 defaultLatinFonts.push_back(QString());
820                 defaultBulletColors.push_back(QString());
821             }
822         }
823         if (isStartElement()) {
824             TRY_READ_IF_NS(a, lvl1pPr)
825             ELSE_TRY_READ_IF_NS(a, lvl2pPr)
826             ELSE_TRY_READ_IF_NS(a, lvl3pPr)
827             ELSE_TRY_READ_IF_NS(a, lvl4pPr)
828             ELSE_TRY_READ_IF_NS(a, lvl5pPr)
829             ELSE_TRY_READ_IF_NS(a, lvl6pPr)
830             ELSE_TRY_READ_IF_NS(a, lvl7pPr)
831             ELSE_TRY_READ_IF_NS(a, lvl8pPr)
832             ELSE_TRY_READ_IF_NS(a, lvl9pPr)
833 //! @todo add ELSE_WRONG_FORMAT
834         }
835         if (isEndElement()) {
836             if (qualifiedName().toString().startsWith(QLatin1String("a:lvl"))) {
837                 defaultParagraphStyles.push_back(m_currentParagraphStyle);
838                 defaultTextStyles.push_back(m_currentTextStyle);
839                 defaultListStyles.push_back(m_currentBulletProperties);
840             }
841         }
842     }
843 
844     READ_EPILOGUE
845 }
846 
847 #undef CURRENT_EL
848 #define CURRENT_EL presentation
849 //! p:presentation handler (Presentation)
850 /*! ECMA-376, 19.2.1.26, p. 2790.
851  Root element.
852  Child elements:
853     - ustDataLst (Customer Data List) §19.3.1.18
854     - custShowLst (List of Custom Shows) §19.2.1.7
855     - [done] defaultTextStyle (Presentation Default Text Style) §19.2.1.8
856     - embeddedFontLst (Embedded Font List) §19.2.1.10
857     - extLst (Extension List) §19.2.1.12
858     - handoutMasterIdLst (List of Handout Master IDs) §19.2.1.15
859     - kinsoku (Kinsoku Settings) §19.2.1.17
860     - modifyVerifier (Modification Verifier) §19.2.1.19
861     - [done] notesMasterIdLst (List of Notes Master IDs) §19.2.1.21
862     - [done] notesSz (Notes Slide Size) §19.2.1.22
863     - photoAlbum (Photo Album Information) §19.2.1.24
864     - [done] sldIdLst (List of Slide IDs) §19.2.1.34
865     - [done] sldMasterIdLst (List of Slide Master IDs) §19.2.1.37
866     - [done] sldSz (Presentation Slide Size) §19.2.1.39
867     - smartTags (Smart Tags) §19.2.1.40
868 */
869 //! @todo support all child elements
read_presentation()870 KoFilter::ConversionStatus PptxXmlDocumentReader::read_presentation()
871 {
872     READ_PROLOGUE
873 
874     QXmlStreamNamespaceDeclarations namespaces = namespaceDeclarations();
875     for (int i = 0; i < namespaces.count(); i++) {
876         debugPptx << "NS prefix:" << namespaces[i].prefix() << "uri:" << namespaces[i].namespaceUri();
877     }
878 
879     if (!m_context->firstReadRound) {
880         debugPptx << "======> Second reading round <======";
881         while (!atEnd()) {
882             readNext();
883             debugPptx << *this;
884             BREAK_IF_END_OF(CURRENT_EL)
885             if (isStartElement()) {
886                 TRY_READ_IF(sldMasterIdLst)
887                 ELSE_TRY_READ_IF(sldIdLst)
888                 ELSE_TRY_READ_IF(sldSz)
889                 ELSE_TRY_READ_IF(notesMasterIdLst)
890                 ELSE_TRY_READ_IF(notesSz)
891                 SKIP_UNKNOWN
892 //! @todo add ELSE_WRONG_FORMAT
893             }
894         }
895     }
896     else {
897         while (!atEnd()) {
898             readNext();
899             BREAK_IF_END_OF(CURRENT_EL)
900             if (isStartElement()) {
901                 TRY_READ_IF(defaultTextStyle)
902                 SKIP_UNKNOWN
903             }
904         }
905         // TODO: Discuss the font-size logic in case it's not provided in the
906         // presentation at the Office Open XML File Format Implementation
907         // forum.  The 18pt value is a result of test files analysis.
908         KoGenStyle style(KoGenStyle::ParagraphStyle, "paragraph");
909         style.setDefaultStyle(true);
910         style.addPropertyPt("fo:font-size", 18, KoGenStyle::TextType);
911 
912         // TODO: Add all defaults defined by the spec. Values defined by
913         // defaultTextStyle/defPPr come on top.
914         style.addPropertyPt("fo:margin-left", EMU_TO_POINT(347663));
915         style.addPropertyPt("fo:margin-top", 0);
916         style.addPropertyPt("fo:margin-right", 0);
917         style.addPropertyPt("fo:margin-bottom", 0);
918         style.addPropertyPt("fo:text-indent", EMU_TO_POINT(-342900));
919 
920         mainStyles->insert(style);
921 
922         style = KoGenStyle(KoGenStyle::TextStyle, "text");
923         style.setDefaultStyle(true);
924         style.addPropertyPt("fo:font-size", 18, KoGenStyle::TextType);
925         mainStyles->insert(style);
926     }
927 
928     if (!m_context->firstReadRound) {
929         // There are double the amount of masterPage frames because we read slideMaster always twice
930         // This means that first frame of the set is always empty and is skipped in the loop
931         unsigned frameCount = d->masterPageFrames.size() / 2;
932         unsigned index = 0;
933         while (index < frameCount) {
934             d->masterPageStyles.push_back(KoGenStyle(KoGenStyle::MasterPageStyle));
935             if (d->sldSzRead) {
936                 KoGenStyle pageLayoutStyle(d->pageLayout.saveOdf());
937                 pageLayoutStyle.setAutoStyleInStylesDotXml(true);
938                 const QString pageLayoutStyleName(mainStyles->insert(pageLayoutStyle, "PM"));
939                 debugPptx << "pageLayoutStyleName:" << pageLayoutStyleName;
940 
941                 d->masterPageStyles[index].addAttribute("style:page-layout-name", pageLayoutStyleName);
942             }
943             if (!d->masterPageDrawStyleNames.at(index).isEmpty()) {
944                d->masterPageStyles[index].addAttribute("draw:style-name", d->masterPageDrawStyleNames.at(index));
945             }
946             d->masterPageStyles[index].addChildElement(QString("frame-2-%1").arg(index), d->masterPageFrames.at((1+index)*2-1));
947             const QString masterPageStyleName(mainStyles->insert(d->masterPageStyles.at(index), "slideMaster"));
948             ++index;
949         }
950     } else {
951         m_context->numberOfItems = m_context->relationships->targetCountWithWord("slideMasters") +
952                                    m_context->relationships->targetCountWithWord("notesMasters") +
953                                    m_context->relationships->targetCountWithWord("slides");
954     }
955 
956     READ_EPILOGUE
957 }
958 
959 #define blipFill_NS "a"
960 
961 // END NAMESPACE p
962 
963 // BEGIN NAMESPACE a
964 
965 #undef MSOOXML_CURRENT_NS
966 #define MSOOXML_CURRENT_NS "a"
967 
968 #include <MsooXmlCommonReaderImpl.h> // this adds a:p, a:pPr, a:t, a:r, etc.
969 
970 #define DRAWINGML_NS "a"
971 #define DRAWINGML_PIC_NS "p" // DrawingML/Picture
972 
973 #include <MsooXmlCommonReaderDrawingMLImpl.h> // this adds p:pic, etc.
974