1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice 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  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "htmlex.hxx"
21 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
22 #include <com/sun/star/drawing/GraphicExportFilter.hpp>
23 #include <com/sun/star/frame/XModel.hpp>
24 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
25 
26 #include <sal/log.hxx>
27 #include <rtl/tencinfo.h>
28 #include <comphelper/processfactory.hxx>
29 #include <o3tl/safeint.hxx>
30 #include <osl/file.hxx>
31 #include <unotools/pathoptions.hxx>
32 #include <unotools/ucbstreamhelper.hxx>
33 #include <com/sun/star/frame/XStorable.hpp>
34 #include <sfx2/frmhtmlw.hxx>
35 #include <sfx2/progress.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/weld.hxx>
38 #include <svx/svditer.hxx>
39 #include <vcl/imaprect.hxx>
40 #include <vcl/imapcirc.hxx>
41 #include <vcl/imappoly.hxx>
42 #include <editeng/eeitem.hxx>
43 #include <editeng/outlobj.hxx>
44 #include <editeng/editobj.hxx>
45 #include <svx/svdopath.hxx>
46 #include <svtools/htmlout.hxx>
47 #include <svtools/colorcfg.hxx>
48 #include <editeng/colritem.hxx>
49 #include <editeng/editeng.hxx>
50 #include <editeng/wghtitem.hxx>
51 #include <editeng/udlnitem.hxx>
52 #include <editeng/postitem.hxx>
53 #include <editeng/crossedoutitem.hxx>
54 #include <editeng/flditem.hxx>
55 #include <svl/style.hxx>
56 #include <editeng/frmdiritem.hxx>
57 #include <svx/svdoutl.hxx>
58 #include <svx/svdogrp.hxx>
59 #include <svx/svdotable.hxx>
60 #include <svx/ImageMapInfo.hxx>
61 #include <tools/urlobj.hxx>
62 #include <svtools/sfxecode.hxx>
63 #include <basegfx/polygon/b2dpolygon.hxx>
64 #include <tools/debug.hxx>
65 #include <tools/diagnose_ex.h>
66 
67 #include <drawdoc.hxx>
68 #include <DrawDocShell.hxx>
69 #include "htmlpublishmode.hxx"
70 #include <Outliner.hxx>
71 #include <sdpage.hxx>
72 #include <strings.hrc>
73 #include <strings.hxx>
74 #include <anminfo.hxx>
75 #include <sdresid.hxx>
76 #include "buttonset.hxx"
77 
78 using namespace ::com::sun::star;
79 using namespace ::com::sun::star::uno;
80 using namespace ::com::sun::star::beans;
81 using namespace ::com::sun::star::frame;
82 using namespace ::com::sun::star::lang;
83 using namespace ::com::sun::star::document;
84 
85 using namespace sdr::table;
86 
87 // get parameter from Itemset
88 #define RESTOHTML( res ) StringToHTMLString(SdResId(res))
89 
90 const char * const pButtonNames[] =
91 {
92     "first-inactive.png",
93     "first.png",
94     "left-inactive.png",
95     "left.png",
96     "right-inactive.png",
97     "right.png",
98     "last-inactive.png",
99     "last.png",
100     "home.png",
101     "text.png",
102     "expand.png",
103     "collapse.png",
104 };
105 
106 #define BTN_FIRST_0 0
107 #define BTN_FIRST_1 1
108 #define BTN_PREV_0  2
109 #define BTN_PREV_1  3
110 #define BTN_NEXT_0  4
111 #define BTN_NEXT_1  5
112 #define BTN_LAST_0  6
113 #define BTN_LAST_1  7
114 #define BTN_INDEX   8
115 #define BTN_TEXT    9
116 #define BTN_MORE    10
117 #define BTN_LESS    11
118 
119 namespace {
120 
121 // Helper class for the simple creation of files local/remote
122 class EasyFile
123 {
124 private:
125     std::unique_ptr<SvStream> pOStm;
126     bool        bOpen;
127 
128 public:
129 
130     EasyFile();
131     ~EasyFile();
132 
133     ErrCode   createStream( const OUString& rUrl, SvStream*& rpStr );
134     void      createFileName(  const OUString& rUrl, OUString& rFileName );
135     void      close();
136 };
137 
138 }
139 
140 // Helper class for the embedding of text attributes into the html output
141 class HtmlState
142 {
143 private:
144     bool mbColor;
145     bool mbWeight;
146     bool mbItalic;
147     bool mbUnderline;
148     bool mbStrike;
149     bool mbLink;
150     Color maColor;
151     Color maDefColor;
152     OUString maLink;
153     OUString maTarget;
154 
155 public:
156     explicit HtmlState( Color aDefColor );
157 
158     OUString SetWeight( bool bWeight );
159     OUString SetItalic( bool bItalic );
160     OUString SetUnderline( bool bUnderline );
161     OUString SetColor( Color aColor );
162     OUString SetStrikeout( bool bStrike );
163     OUString SetLink( const OUString& aLink, const OUString& aTarget );
164     OUString Flush();
165 };
166 
167 // close all still open tags
Flush()168 OUString HtmlState::Flush()
169 {
170     OUString aStr = SetWeight(false)
171                   + SetItalic(false)
172                   + SetUnderline(false)
173                   + SetStrikeout(false)
174                   + SetColor(maDefColor)
175                   + SetLink("","");
176 
177     return aStr;
178 }
179 
180 // c'tor with default color for the page
HtmlState(Color aDefColor)181 HtmlState::HtmlState( Color aDefColor )
182   : mbColor(false),
183     mbWeight(false),
184     mbItalic(false),
185     mbUnderline(false),
186     mbStrike(false),
187     mbLink(false),
188     maDefColor(aDefColor)
189 {
190 }
191 
192 // enables/disables bold print
SetWeight(bool bWeight)193 OUString HtmlState::SetWeight( bool bWeight )
194 {
195     OUString aStr;
196 
197     if(bWeight && !mbWeight)
198         aStr = "<b>";
199     else if(!bWeight && mbWeight)
200         aStr = "</b>";
201 
202     mbWeight = bWeight;
203     return aStr;
204 }
205 
206 // enables/disables italic
207 
SetItalic(bool bItalic)208 OUString HtmlState::SetItalic( bool bItalic )
209 {
210     OUString aStr;
211 
212     if(bItalic && !mbItalic)
213         aStr = "<i>";
214     else if(!bItalic && mbItalic)
215         aStr = "</i>";
216 
217     mbItalic = bItalic;
218     return aStr;
219 }
220 
221 // enables/disables underlines
222 
SetUnderline(bool bUnderline)223 OUString HtmlState::SetUnderline( bool bUnderline )
224 {
225     OUString aStr;
226 
227     if(bUnderline && !mbUnderline)
228         aStr = "<u>";
229     else if(!bUnderline && mbUnderline)
230         aStr = "</u>";
231 
232     mbUnderline = bUnderline;
233     return aStr;
234 }
235 
236 // enables/disables strike through
SetStrikeout(bool bStrike)237 OUString HtmlState::SetStrikeout( bool bStrike )
238 {
239     OUString aStr;
240 
241     if(bStrike && !mbStrike)
242         aStr = "<strike>";
243     else if(!bStrike && mbStrike)
244         aStr = "</strike>";
245 
246     mbStrike = bStrike;
247     return aStr;
248 }
249 
250 // Sets the specified text color
SetColor(Color aColor)251 OUString HtmlState::SetColor( Color aColor )
252 {
253     OUString aStr;
254 
255     if(mbColor && aColor == maColor)
256         return aStr;
257 
258     if(mbColor)
259     {
260         aStr = "</font>";
261         mbColor = false;
262     }
263 
264     if(aColor != maDefColor)
265     {
266         maColor = aColor;
267         aStr += "<font color=\"" + HtmlExport::ColorToHTMLString(aColor) + "\">";
268         mbColor = true;
269     }
270 
271     return aStr;
272 }
273 
274 // enables/disables a hyperlink
SetLink(const OUString & aLink,const OUString & aTarget)275 OUString HtmlState::SetLink( const OUString& aLink, const OUString& aTarget )
276 {
277     OUString aStr;
278 
279     if(mbLink&&maLink == aLink&&maTarget==aTarget)
280         return aStr;
281 
282     if(mbLink)
283     {
284         aStr = "</a>";
285         mbLink = false;
286     }
287 
288     if (!aLink.isEmpty())
289     {
290         aStr += "<a href=\"" + aLink;
291         if (!aTarget.isEmpty())
292         {
293             aStr += "\" target=\"" + aTarget;
294         }
295         aStr += "\">";
296         mbLink = true;
297         maLink = aLink;
298         maTarget = aTarget;
299     }
300 
301     return aStr;
302 }
303 namespace
304 {
305 
getParagraphStyle(SdrOutliner * pOutliner,sal_Int32 nPara)306 OUString getParagraphStyle( SdrOutliner* pOutliner, sal_Int32 nPara )
307 {
308     SfxItemSet aParaSet( pOutliner->GetParaAttribs( nPara ) );
309 
310     OUString sStyle;
311 
312     if( aParaSet.GetItem<SvxFrameDirectionItem>( EE_PARA_WRITINGDIR )->GetValue() == SvxFrameDirection::Horizontal_RL_TB )
313     {
314 
315         sStyle = "direction: rtl;";
316     }
317     else
318     {
319         // This is the default so don't write it out
320         // sStyle += "direction: ltr;";
321     }
322     return sStyle;
323 }
324 
lclAppendStyle(OUStringBuffer & aBuffer,std::u16string_view aTag,std::u16string_view aStyle)325 void lclAppendStyle(OUStringBuffer& aBuffer, std::u16string_view aTag, std::u16string_view aStyle)
326 {
327     if (aStyle.empty())
328         aBuffer.append(OUString::Concat("<") + aTag + ">");
329     else
330         aBuffer.append(OUString::Concat("<") + aTag + " style=\"" + aStyle + "\">");
331 }
332 
333 } // anonymous namespace
334 
335 constexpr OUStringLiteral gaHTMLHeader(
336             u"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
337             "     \"http://www.w3.org/TR/html4/transitional.dtd\">\r\n"
338             "<html>\r\n<head>\r\n" );
339 
340 constexpr OUStringLiteral gaHTMLExtension = u"" STR_HTMLEXP_DEFAULT_EXTENSION;
341 
342 // constructor for the html export helper classes
HtmlExport(const OUString & aPath,const Sequence<PropertyValue> & rParams,SdDrawDocument * pExpDoc,sd::DrawDocShell * pDocShell)343 HtmlExport::HtmlExport(
344     const OUString& aPath,
345     const Sequence< PropertyValue >& rParams,
346     SdDrawDocument* pExpDoc,
347     sd::DrawDocShell* pDocShell )
348     :   maPath( aPath ),
349         mpDoc(pExpDoc),
350         mpDocSh( pDocShell ),
351         meEC(),
352         meMode( PUBLISH_SINGLE_DOCUMENT ),
353         mbContentsPage(false),
354         mnButtonThema(-1),
355         mnWidthPixel( PUB_MEDRES_WIDTH ),
356         meFormat( FORMAT_JPG ),
357         mbNotes(false),
358         mnCompression( -1 ),
359         mbDownload( false ),
360         mbSlideSound(true),
361         mbHiddenSlides(true),
362         mbUserAttr(false),
363         maTextColor(COL_BLACK),
364         maBackColor(COL_WHITE),
365         mbDocColors(false),
366         maIndexUrl("index"),
367         meScript( SCRIPT_ASP ),
368         mpButtonSet( new ButtonSet() )
369 {
370     bool bChange = mpDoc->IsChanged();
371 
372     maIndexUrl += gaHTMLExtension;
373 
374     InitExportParameters( rParams );
375 
376     switch( meMode )
377     {
378     case PUBLISH_HTML:
379     case PUBLISH_FRAMES:
380         ExportHtml();
381         break;
382     case PUBLISH_WEBCAST:
383         ExportWebCast();
384         break;
385     case PUBLISH_KIOSK:
386         ExportKiosk();
387         break;
388     case PUBLISH_SINGLE_DOCUMENT:
389         ExportSingleDocument();
390         break;
391     }
392 
393     mpDoc->SetChanged(bChange);
394 }
395 
~HtmlExport()396 HtmlExport::~HtmlExport()
397 {
398 }
399 
400 // get common export parameters from item set
InitExportParameters(const Sequence<PropertyValue> & rParams)401 void HtmlExport::InitExportParameters( const Sequence< PropertyValue >& rParams )
402 {
403     mbImpress = mpDoc->GetDocumentType() == DocumentType::Impress;
404 
405     OUString aStr;
406     for( const PropertyValue& rParam : rParams )
407     {
408         if ( rParam.Name == "PublishMode" )
409         {
410             sal_Int32 temp = 0;
411             rParam.Value >>= temp;
412             meMode = static_cast<HtmlPublishMode>(temp);
413         }
414         else if ( rParam.Name == "IndexURL" )
415         {
416             rParam.Value >>= aStr;
417             maIndexUrl = aStr;
418         }
419         else if ( rParam.Name == "Format" )
420         {
421             sal_Int32 temp = 0;
422             rParam.Value >>= temp;
423             meFormat = static_cast<PublishingFormat>(temp);
424         }
425         else if ( rParam.Name == "Compression" )
426         {
427             rParam.Value >>= aStr;
428             OUString aTmp( aStr );
429             if(!aTmp.isEmpty())
430             {
431                 aTmp = aTmp.replaceFirst("%", "");
432                 mnCompression = static_cast<sal_Int16>(aTmp.toInt32());
433             }
434         }
435         else if ( rParam.Name == "Width" )
436         {
437             sal_Int32 temp = 0;
438             rParam.Value >>= temp;
439             mnWidthPixel = static_cast<sal_uInt16>(temp);
440         }
441         else if ( rParam.Name == "UseButtonSet" )
442         {
443             sal_Int32 temp = 0;
444             rParam.Value >>= temp;
445             mnButtonThema = static_cast<sal_Int16>(temp);
446         }
447         else if ( rParam.Name == "IsExportNotes" )
448         {
449             if( mbImpress )
450             {
451                 bool temp = false;
452                 rParam.Value >>= temp;
453                 mbNotes = temp;
454             }
455         }
456         else if ( rParam.Name == "IsExportContentsPage" )
457         {
458             bool temp = false;
459             rParam.Value >>= temp;
460             mbContentsPage = temp;
461         }
462         else if ( rParam.Name == "Author" )
463         {
464             rParam.Value >>= aStr;
465             maAuthor = aStr;
466         }
467         else if ( rParam.Name == "EMail" )
468         {
469             rParam.Value >>= aStr;
470             maEMail = aStr;
471         }
472         else if ( rParam.Name == "HomepageURL" )
473         {
474             rParam.Value >>= aStr;
475             maHomePage = aStr;
476         }
477         else if ( rParam.Name == "UserText" )
478         {
479             rParam.Value >>= aStr;
480             maInfo = aStr;
481         }
482         else if ( rParam.Name == "EnableDownload" )
483         {
484             bool temp = false;
485             rParam.Value >>= temp;
486             mbDownload = temp;
487         }
488         else if ( rParam.Name == "SlideSound" )
489         {
490             bool temp = true;
491             rParam.Value >>= temp;
492             mbSlideSound = temp;
493         }
494         else if ( rParam.Name == "HiddenSlides" )
495         {
496             bool temp = true;
497             rParam.Value >>= temp;
498             mbHiddenSlides = temp;
499         }
500         else if ( rParam.Name == "BackColor" )
501         {
502             Color temp;
503             rParam.Value >>= temp;
504             maBackColor = temp;
505             mbUserAttr = true;
506         }
507         else if ( rParam.Name == "TextColor" )
508         {
509             Color temp;
510             rParam.Value >>= temp;
511             maTextColor = temp;
512             mbUserAttr = true;
513         }
514         else if ( rParam.Name == "LinkColor" )
515         {
516             Color temp ;
517             rParam.Value >>= temp;
518             maLinkColor = temp;
519             mbUserAttr = true;
520         }
521         else if ( rParam.Name == "VLinkColor" )
522         {
523             Color temp;
524             rParam.Value >>= temp;
525             maVLinkColor = temp;
526             mbUserAttr = true;
527         }
528         else if ( rParam.Name == "ALinkColor" )
529         {
530             Color temp;
531             rParam.Value >>= temp;
532             maALinkColor = temp;
533             mbUserAttr = true;
534         }
535         else if ( rParam.Name == "IsUseDocumentColors" )
536         {
537             bool temp = false;
538             rParam.Value >>= temp;
539             mbDocColors = temp;
540         }
541         else if ( rParam.Name == "KioskSlideDuration" )
542         {
543             double temp = 0.0;
544             rParam.Value >>= temp;
545             mfSlideDuration = temp;
546             mbAutoSlide = true;
547         }
548         else if ( rParam.Name == "KioskEndless" )
549         {
550             bool temp = false;
551             rParam.Value >>= temp;
552             mbEndless = temp;
553         }
554         else if ( rParam.Name == "WebCastCGIURL" )
555         {
556             rParam.Value >>= aStr;
557             maCGIPath = aStr;
558         }
559         else if ( rParam.Name == "WebCastTargetURL" )
560         {
561             rParam.Value >>= aStr;
562             maURLPath = aStr;
563         }
564         else if ( rParam.Name == "WebCastScriptLanguage" )
565         {
566             rParam.Value >>= aStr;
567             if ( aStr == "asp" )
568             {
569                 meScript = SCRIPT_ASP;
570             }
571             else
572             {
573                 meScript = SCRIPT_PERL;
574             }
575         }
576         else
577         {
578             OSL_FAIL("Unknown property for html export detected!");
579         }
580     }
581 
582     if( meMode == PUBLISH_KIOSK )
583     {
584         mbContentsPage = false;
585         mbNotes = false;
586 
587     }
588 
589     // calculate image sizes
590     SdPage* pPage = mpDoc->GetSdPage(0, PageKind::Standard);
591     Size aTmpSize( pPage->GetSize() );
592     double dRatio=static_cast<double>(aTmpSize.Width())/aTmpSize.Height();
593 
594     mnHeightPixel = static_cast<sal_uInt16>(mnWidthPixel/dRatio);
595 
596     // we come up with a destination...
597 
598     INetURLObject aINetURLObj( maPath );
599     DBG_ASSERT( aINetURLObj.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
600 
601     maExportPath = aINetURLObj.GetPartBeforeLastName(); // with trailing '/'
602     maIndex = aINetURLObj.GetLastName();
603 
604     mnSdPageCount = mpDoc->GetSdPageCount( PageKind::Standard );
605     for( sal_uInt16 nPage = 0; nPage < mnSdPageCount; nPage++ )
606     {
607         pPage = mpDoc->GetSdPage( nPage, PageKind::Standard );
608 
609         if( mbHiddenSlides || !pPage->IsExcluded() )
610         {
611             maPages.push_back( pPage );
612             maNotesPages.push_back( mpDoc->GetSdPage( nPage, PageKind::Notes ) );
613         }
614     }
615     mnSdPageCount = maPages.size();
616 
617     mbFrames = meMode == PUBLISH_FRAMES;
618 
619     maDocFileName = maIndex;
620 }
621 
ExportSingleDocument()622 void HtmlExport::ExportSingleDocument()
623 {
624     SdrOutliner* pOutliner = mpDoc->GetInternalOutliner();
625 
626     maPageNames.resize(mnSdPageCount);
627 
628     mnPagesWritten = 0;
629     InitProgress(mnSdPageCount);
630 
631     OUStringBuffer aStr(gaHTMLHeader);
632     aStr.append(DocumentMetadata());
633     aStr.append("\r\n");
634     aStr.append("</head>\r\n");
635     aStr.append(CreateBodyTag());
636 
637     for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; ++nSdPage)
638     {
639         SdPage* pPage = maPages[nSdPage];
640         maPageNames[nSdPage] = pPage->GetName();
641 
642         if( mbDocColors )
643         {
644             SetDocColors( pPage );
645         }
646 
647         // page title
648         OUString sTitleText(CreateTextForTitle(pOutliner, pPage, pPage->GetPageBackgroundColor()));
649         OUString sStyle;
650 
651         if (nSdPage != 0) // First page - no need for a page brake here
652             sStyle += "page-break-before:always; ";
653         sStyle += getParagraphStyle(pOutliner, 0);
654 
655         lclAppendStyle(aStr, u"h1", sStyle);
656 
657         aStr.append(sTitleText);
658         aStr.append("</h1>\r\n");
659 
660         // write outline text
661         aStr.append(CreateTextForPage( pOutliner, pPage, true, pPage->GetPageBackgroundColor() ));
662 
663         // notes
664         if(mbNotes)
665         {
666             SdPage* pNotesPage = maNotesPages[ nSdPage ];
667             OUString aNotesStr( CreateTextForNotesPage( pOutliner, pNotesPage, maBackColor) );
668 
669             if (!aNotesStr.isEmpty())
670             {
671                 aStr.append("<br>\r\n<h3>");
672                 aStr.append(RESTOHTML(STR_HTMLEXP_NOTES));
673                 aStr.append(":</h3>\r\n");
674 
675                 aStr.append(aNotesStr);
676             }
677         }
678 
679         if (mpProgress)
680             mpProgress->SetState(++mnPagesWritten);
681 
682     }
683 
684     // close page
685     aStr.append("</body>\r\n</html>");
686 
687     WriteHtml(maDocFileName, false, aStr.makeStringAndClear());
688 
689     pOutliner->Clear();
690     ResetProgress();
691 }
692 
693 // exports the (in the c'tor specified impress document) to html
ExportHtml()694 void HtmlExport::ExportHtml()
695 {
696     if(mbUserAttr)
697     {
698         if( maTextColor == COL_AUTO )
699         {
700             if( !maBackColor.IsDark() )
701                 maTextColor = COL_BLACK;
702         }
703     }
704     else if( mbDocColors )
705     {
706         // default colors for the color schema 'From Document'
707         SetDocColors();
708         maFirstPageColor = maBackColor;
709     }
710 
711     // get name for downloadable presentation if needed
712     if( mbDownload )
713     {
714         // fade out separator search and extension
715         sal_Int32 nSepPos = maDocFileName.indexOf('.');
716         if (nSepPos != -1)
717             maDocFileName = maDocFileName.copy(0, nSepPos);
718 
719         maDocFileName += ".odp";
720     }
721 
722     sal_uInt16 nProgrCount = mnSdPageCount;
723     nProgrCount += mbImpress?mnSdPageCount:0;
724     nProgrCount += mbContentsPage?1:0;
725     nProgrCount += (mbFrames && mbNotes)?mnSdPageCount:0;
726     nProgrCount += mbFrames ? 8 : 0;
727     InitProgress( nProgrCount );
728 
729     mpDocSh->SetWaitCursor( true );
730 
731     // Exceptions are cool...
732 
733     CreateFileNames();
734 
735     // this is not a true while
736     while( true )
737     {
738         if( checkForExistingFiles() )
739             break;
740 
741         if( !CreateImagesForPresPages() )
742             break;
743 
744         if( mbContentsPage &&
745            !CreateImagesForPresPages( true ) )
746             break;
747 
748         if( !CreateHtmlForPresPages() )
749             break;
750 
751         if( mbImpress )
752             if( !CreateHtmlTextForPresPages() )
753                 break;
754 
755         if( mbFrames )
756         {
757             if( !CreateFrames() )
758                 break;
759 
760             if( !CreateOutlinePages() )
761                 break;
762 
763             if( !CreateNavBarFrames() )
764                 break;
765 
766             if( mbNotes && mbImpress )
767                 if( !CreateNotesPages() )
768                     break;
769 
770         }
771 
772         if( mbContentsPage )
773             if( !CreateContentPage() )
774                 break;
775 
776         CreateBitmaps();
777 
778         mpDocSh->SetWaitCursor( false );
779         ResetProgress();
780 
781         if( mbDownload )
782             SavePresentation();
783 
784         return;
785     }
786 
787     // if we get to this point the export was
788     // canceled by the user after an error
789     mpDocSh->SetWaitCursor( false );
790     ResetProgress();
791 }
792 
SetDocColors(SdPage * pPage)793 void HtmlExport::SetDocColors( SdPage* pPage )
794 {
795     if( pPage == nullptr )
796         pPage = mpDoc->GetSdPage(0, PageKind::Standard);
797 
798     svtools::ColorConfig aConfig;
799     maVLinkColor = aConfig.GetColorValue(svtools::LINKSVISITED).nColor;
800     maALinkColor = aConfig.GetColorValue(svtools::LINKS).nColor;
801     maLinkColor  = aConfig.GetColorValue(svtools::LINKS).nColor;
802     maTextColor  = COL_BLACK;
803 
804     SfxStyleSheet* pSheet = nullptr;
805 
806     if( mpDoc->GetDocumentType() == DocumentType::Impress )
807     {
808         // default text color from the outline template of the first page
809         pSheet = pPage->GetStyleSheetForPresObj(PresObjKind::Outline);
810         if(pSheet == nullptr)
811             pSheet = pPage->GetStyleSheetForPresObj(PresObjKind::Text);
812         if(pSheet == nullptr)
813             pSheet = pPage->GetStyleSheetForPresObj(PresObjKind::Title);
814     }
815 
816     if(pSheet == nullptr)
817         pSheet = mpDoc->GetDefaultStyleSheet();
818 
819     if(pSheet)
820     {
821         SfxItemSet& rSet = pSheet->GetItemSet();
822         if(rSet.GetItemState(EE_CHAR_COLOR) == SfxItemState::SET)
823             maTextColor = rSet.GetItem<SvxColorItem>(EE_CHAR_COLOR)->GetValue();
824     }
825 
826     // default background from the background of the master page of the first page
827     maBackColor = pPage->GetPageBackgroundColor();
828 
829     if( maTextColor == COL_AUTO )
830     {
831         if( !maBackColor.IsDark() )
832             maTextColor = COL_BLACK;
833     }
834 }
835 
InitProgress(sal_uInt16 nProgrCount)836 void HtmlExport::InitProgress( sal_uInt16 nProgrCount )
837 {
838     mpProgress.reset(new SfxProgress( mpDocSh, SdResId(STR_CREATE_PAGES), nProgrCount ));
839 }
840 
ResetProgress()841 void HtmlExport::ResetProgress()
842 {
843     mpProgress.reset();
844 }
845 
ExportKiosk()846 void HtmlExport::ExportKiosk()
847 {
848     mnPagesWritten = 0;
849     InitProgress( 2*mnSdPageCount );
850 
851     CreateFileNames();
852     if( !checkForExistingFiles() )
853     {
854         if( CreateImagesForPresPages() )
855             CreateHtmlForPresPages();
856     }
857 
858     ResetProgress();
859 }
860 
861 // Export Document with WebCast (TM) Technology
ExportWebCast()862 void HtmlExport::ExportWebCast()
863 {
864     mnPagesWritten = 0;
865     InitProgress( mnSdPageCount + 9 );
866 
867     mpDocSh->SetWaitCursor( true );
868 
869     CreateFileNames();
870 
871     if (maCGIPath.isEmpty())
872         maCGIPath = ".";
873 
874     if (!maCGIPath.endsWith("/"))
875         maCGIPath += "/";
876 
877     if( meScript == SCRIPT_ASP )
878     {
879         maURLPath = "./";
880     }
881     else
882     {
883         if (maURLPath.isEmpty())
884             maURLPath = ".";
885 
886         if (!maURLPath.endsWith("/"))
887             maURLPath += "/";
888     }
889 
890     // this is not a true while
891     while(true)
892     {
893         if( checkForExistingFiles() )
894             break;
895 
896         if(!CreateImagesForPresPages())
897             break;
898 
899         if( meScript == SCRIPT_ASP )
900         {
901             if(!CreateASPScripts())
902                 break;
903         }
904         else
905         {
906             if(!CreatePERLScripts())
907                 break;
908         }
909 
910         if(!CreateImageFileList())
911             break;
912 
913         if(!CreateImageNumberFile())
914             break;
915 
916         break;
917     }
918 
919     mpDocSh->SetWaitCursor( false );
920     ResetProgress();
921 }
922 
923 // Save the presentation as a downloadable file in the dest directory
SavePresentation()924 bool HtmlExport::SavePresentation()
925 {
926     meEC.SetContext( STR_HTMLEXP_ERROR_CREATE_FILE, maDocFileName );
927 
928     OUString aURL(maExportPath + maDocFileName);
929 
930     mpDocSh->EnableSetModified();
931 
932     try
933     {
934         uno::Reference< frame::XStorable > xStorable( mpDoc->getUnoModel(), uno::UNO_QUERY );
935         if( xStorable.is() )
936         {
937             uno::Sequence< beans::PropertyValue > aProperties( 2 );
938             aProperties[ 0 ].Name = "Overwrite";
939             aProperties[ 0 ].Value <<= true;
940             aProperties[ 1 ].Name = "FilterName";
941             aProperties[ 1 ].Value <<= OUString("impress8");
942             xStorable->storeToURL( aURL, aProperties );
943 
944             mpDocSh->EnableSetModified( false );
945 
946             return true;
947         }
948     }
949     catch( Exception& )
950     {
951     }
952 
953     mpDocSh->EnableSetModified( false );
954 
955     return false;
956 }
957 
958 // create image files
CreateImagesForPresPages(bool bThumbnail)959 bool HtmlExport::CreateImagesForPresPages( bool bThumbnail)
960 {
961     try
962     {
963         Reference < XComponentContext > xContext = ::comphelper::getProcessComponentContext();
964 
965         Reference< drawing::XGraphicExportFilter > xGraphicExporter = drawing::GraphicExportFilter::create( xContext );
966 
967         Sequence< PropertyValue > aFilterData(((meFormat==FORMAT_JPG)&&(mnCompression != -1))? 3 : 2);
968         aFilterData[0].Name = "PixelWidth";
969         aFilterData[0].Value <<= static_cast<sal_Int32>(bThumbnail ? PUB_THUMBNAIL_WIDTH : mnWidthPixel );
970         aFilterData[1].Name = "PixelHeight";
971         aFilterData[1].Value <<= static_cast<sal_Int32>(bThumbnail ? PUB_THUMBNAIL_HEIGHT : mnHeightPixel);
972         if((meFormat==FORMAT_JPG)&&(mnCompression != -1))
973         {
974             aFilterData[2].Name = "Quality";
975             aFilterData[2].Value <<= static_cast<sal_Int32>(mnCompression);
976         }
977 
978         Sequence< PropertyValue > aDescriptor( 3 );
979         aDescriptor[0].Name = "URL";
980         aDescriptor[1].Name = "FilterName";
981         OUString sFormat;
982         if( meFormat == FORMAT_PNG )
983             sFormat = "PNG";
984         else if( meFormat == FORMAT_GIF )
985             sFormat = "GIF";
986         else
987             sFormat = "JPG";
988 
989         aDescriptor[1].Value <<= sFormat;
990         aDescriptor[2].Name = "FilterData";
991         aDescriptor[2].Value <<= aFilterData;
992 
993         for (sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
994         {
995             SdPage* pPage = maPages[ nSdPage ];
996 
997             OUString aFull(maExportPath);
998             if (bThumbnail)
999                 aFull += maThumbnailFiles[nSdPage];
1000             else
1001                 aFull += maImageFiles[nSdPage];
1002 
1003             aDescriptor[0].Value <<= aFull;
1004 
1005             Reference< XComponent > xPage( pPage->getUnoPage(), UNO_QUERY );
1006             xGraphicExporter->setSourceDocument( xPage );
1007             xGraphicExporter->filter( aDescriptor );
1008 
1009             if (mpProgress)
1010                 mpProgress->SetState(++mnPagesWritten);
1011         }
1012     }
1013     catch( Exception& )
1014     {
1015         return false;
1016     }
1017 
1018     return true;
1019 }
1020 
1021 // get SdrTextObject with layout text of this page
GetLayoutTextObject(SdrPage const * pPage)1022 SdrTextObj* HtmlExport::GetLayoutTextObject(SdrPage const * pPage)
1023 {
1024     const size_t nObjectCount = pPage->GetObjCount();
1025     SdrTextObj*     pResult      = nullptr;
1026 
1027     for (size_t nObject = 0; nObject < nObjectCount; ++nObject)
1028     {
1029         SdrObject* pObject = pPage->GetObj(nObject);
1030         if (pObject->GetObjInventor() == SdrInventor::Default &&
1031             pObject->GetObjIdentifier() == OBJ_OUTLINETEXT)
1032         {
1033             pResult = static_cast<SdrTextObj*>(pObject);
1034             break;
1035         }
1036     }
1037     return pResult;
1038 }
1039 
1040 // create HTML text version of impress pages
CreateMetaCharset()1041 OUString HtmlExport::CreateMetaCharset()
1042 {
1043     OUString aStr;
1044     const char *pCharSet = rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8 );
1045     if ( pCharSet )
1046     {
1047         aStr = "  <meta HTTP-EQUIV=CONTENT-TYPE CONTENT=\"text/html; charset=" +
1048                OUString::createFromAscii(pCharSet) + "\">\r\n";
1049     }
1050     return aStr;
1051 }
1052 
DocumentMetadata() const1053 OUString HtmlExport::DocumentMetadata() const
1054 {
1055     SvMemoryStream aStream;
1056 
1057     uno::Reference<document::XDocumentProperties> xDocProps;
1058     if (mpDocSh)
1059     {
1060         uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1061             mpDocSh->GetModel(), uno::UNO_QUERY_THROW);
1062         xDocProps.set(xDPS->getDocumentProperties());
1063     }
1064 
1065     OUString aNonConvertableCharacters;
1066 
1067     SfxFrameHTMLWriter::Out_DocInfo(aStream, maDocFileName, xDocProps,
1068             "  ", RTL_TEXTENCODING_UTF8,
1069             &aNonConvertableCharacters);
1070 
1071     const sal_uInt64 nLen = aStream.GetSize();
1072     OSL_ENSURE(nLen < o3tl::make_unsigned(SAL_MAX_INT32), "Stream can't fit in OString");
1073     OString aData(static_cast<const char*>(aStream.GetData()), static_cast<sal_Int32>(nLen));
1074 
1075     return OStringToOUString(aData, RTL_TEXTENCODING_UTF8);
1076 }
1077 
CreateHtmlTextForPresPages()1078 bool HtmlExport::CreateHtmlTextForPresPages()
1079 {
1080     bool bOk = true;
1081 
1082     SdrOutliner* pOutliner = mpDoc->GetInternalOutliner();
1083 
1084     for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount && bOk; nSdPage++)
1085     {
1086         SdPage* pPage = maPages[ nSdPage ];
1087 
1088         if( mbDocColors )
1089         {
1090             SetDocColors( pPage );
1091         }
1092 
1093         // HTML head
1094         OUStringBuffer aStr(gaHTMLHeader);
1095         aStr.append(CreateMetaCharset());
1096         aStr.append("  <title>");
1097         aStr.append(StringToHTMLString(maPageNames[nSdPage]));
1098         aStr.append("</title>\r\n");
1099         aStr.append("</head>\r\n");
1100         aStr.append(CreateBodyTag());
1101 
1102         // navigation bar
1103         aStr.append(CreateNavBar(nSdPage, true));
1104 
1105         // page title
1106         OUString sTitleText( CreateTextForTitle(pOutliner,pPage, pPage->GetPageBackgroundColor()) );
1107         lclAppendStyle(aStr, u"h1", getParagraphStyle(pOutliner, 0));
1108         aStr.append(sTitleText);
1109         aStr.append("</h1>\r\n");
1110 
1111         // write outline text
1112         aStr.append(CreateTextForPage( pOutliner, pPage, true, pPage->GetPageBackgroundColor() ));
1113 
1114         // notes
1115         if(mbNotes)
1116         {
1117             SdPage* pNotesPage = maNotesPages[ nSdPage ];
1118             OUString aNotesStr( CreateTextForNotesPage( pOutliner, pNotesPage, maBackColor) );
1119 
1120             if (!aNotesStr.isEmpty())
1121             {
1122                 aStr.append("<br>\r\n<h3>");
1123                 aStr.append(RESTOHTML(STR_HTMLEXP_NOTES));
1124                 aStr.append(":</h3>\r\n");
1125 
1126                 aStr.append(aNotesStr);
1127             }
1128         }
1129 
1130         // close page
1131         aStr.append("</body>\r\n</html>");
1132 
1133         bOk = WriteHtml(maTextFiles[nSdPage], false, aStr.makeStringAndClear());
1134 
1135         if (mpProgress)
1136             mpProgress->SetState(++mnPagesWritten);
1137 
1138     }
1139 
1140     pOutliner->Clear();
1141 
1142     return bOk;
1143 }
1144 
1145 /** exports the given html data into a non unicode file in the current export path with
1146     the given filename */
WriteHtml(const OUString & rFileName,bool bAddExtension,std::u16string_view rHtmlData)1147 bool HtmlExport::WriteHtml( const OUString& rFileName, bool bAddExtension, std::u16string_view rHtmlData )
1148 {
1149     ErrCode nErr = ERRCODE_NONE;
1150 
1151     OUString aFileName( rFileName );
1152     if( bAddExtension )
1153         aFileName += gaHTMLExtension;
1154 
1155     meEC.SetContext( STR_HTMLEXP_ERROR_CREATE_FILE, rFileName );
1156     EasyFile aFile;
1157     SvStream* pStr;
1158     OUString aFull(maExportPath + aFileName);
1159     nErr = aFile.createStream(aFull , pStr);
1160     if(nErr == ERRCODE_NONE)
1161     {
1162         OString aStr(OUStringToOString(rHtmlData, RTL_TEXTENCODING_UTF8));
1163         pStr->WriteOString( aStr );
1164         aFile.close();
1165     }
1166 
1167     if( nErr != ERRCODE_NONE )
1168         ErrorHandler::HandleError(nErr);
1169 
1170     return nErr == ERRCODE_NONE;
1171 }
1172 
1173 /** creates an outliner text for the title objects of a page
1174  */
CreateTextForTitle(SdrOutliner * pOutliner,SdPage * pPage,const Color & rBackgroundColor)1175 OUString HtmlExport::CreateTextForTitle( SdrOutliner* pOutliner, SdPage* pPage, const Color& rBackgroundColor )
1176 {
1177     SdrTextObj* pTO = static_cast<SdrTextObj*>(pPage->GetPresObj(PresObjKind::Title));
1178     if(!pTO)
1179         pTO = GetLayoutTextObject(pPage);
1180 
1181     if (pTO && !pTO->IsEmptyPresObj())
1182     {
1183         OutlinerParaObject* pOPO = pTO->GetOutlinerParaObject();
1184         if(pOPO && pOutliner->GetParagraphCount() != 0)
1185         {
1186             pOutliner->Clear();
1187             pOutliner->SetText(*pOPO);
1188             return ParagraphToHTMLString(pOutliner,0, rBackgroundColor);
1189         }
1190     }
1191 
1192     return OUString();
1193 }
1194 
1195 // creates an outliner text for a page
CreateTextForPage(SdrOutliner * pOutliner,SdPage const * pPage,bool bHeadLine,const Color & rBackgroundColor)1196 OUString HtmlExport::CreateTextForPage(SdrOutliner* pOutliner, SdPage const * pPage,
1197                                        bool bHeadLine, const Color& rBackgroundColor)
1198 {
1199     OUStringBuffer aStr;
1200 
1201     for (size_t i = 0; i <pPage->GetObjCount(); ++i )
1202     {
1203         SdrObject* pObject = pPage->GetObj(i);
1204         PresObjKind eKind = pPage->GetPresObjKind(pObject);
1205 
1206         switch (eKind)
1207         {
1208             case PresObjKind::NONE:
1209             {
1210                 if (pObject->GetObjIdentifier() == OBJ_GRUP)
1211                 {
1212                     SdrObjGroup* pObjectGroup = static_cast<SdrObjGroup*>(pObject);
1213                     WriteObjectGroup(aStr, pObjectGroup, pOutliner, rBackgroundColor, false);
1214                 }
1215                 else if (pObject->GetObjIdentifier() == OBJ_TABLE)
1216                 {
1217                     SdrTableObj* pTableObject = static_cast<SdrTableObj*>(pObject);
1218                     WriteTable(aStr, pTableObject, pOutliner, rBackgroundColor);
1219                 }
1220                 else
1221                 {
1222                     if (pObject->GetOutlinerParaObject())
1223                     {
1224                         WriteOutlinerParagraph(aStr, pOutliner, pObject->GetOutlinerParaObject(), rBackgroundColor, false);
1225                     }
1226                 }
1227             }
1228             break;
1229 
1230             case PresObjKind::Table:
1231             {
1232                 SdrTableObj* pTableObject = static_cast<SdrTableObj*>(pObject);
1233                 WriteTable(aStr, pTableObject, pOutliner, rBackgroundColor);
1234             }
1235             break;
1236 
1237             case PresObjKind::Text:
1238             case PresObjKind::Outline:
1239             {
1240                 SdrTextObj* pTextObject = static_cast<SdrTextObj*>(pObject);
1241                 if (pTextObject->IsEmptyPresObj())
1242                     continue;
1243                 WriteOutlinerParagraph(aStr, pOutliner, pTextObject->GetOutlinerParaObject(), rBackgroundColor, bHeadLine);
1244             }
1245             break;
1246 
1247             default:
1248                 break;
1249         }
1250     }
1251     return aStr.makeStringAndClear();
1252 }
1253 
WriteTable(OUStringBuffer & aStr,SdrTableObj const * pTableObject,SdrOutliner * pOutliner,const Color & rBackgroundColor)1254 void HtmlExport::WriteTable(OUStringBuffer& aStr, SdrTableObj const * pTableObject, SdrOutliner* pOutliner, const Color& rBackgroundColor)
1255 {
1256     CellPos aStart, aEnd;
1257 
1258     aStart = SdrTableObj::getFirstCell();
1259     aEnd = pTableObject->getLastCell();
1260 
1261     sal_Int32 nColCount = pTableObject->getColumnCount();
1262     aStr.append("<table>\r\n");
1263     for (sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++)
1264     {
1265         aStr.append("  <tr>\r\n");
1266         for (sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++)
1267         {
1268             aStr.append("    <td>\r\n");
1269             sal_Int32 nCellIndex = nRow * nColCount + nCol;
1270             SdrText* pText = pTableObject->getText(nCellIndex);
1271 
1272             if (pText == nullptr)
1273                 continue;
1274             WriteOutlinerParagraph(aStr, pOutliner, pText->GetOutlinerParaObject(), rBackgroundColor, false);
1275             aStr.append("    </td>\r\n");
1276         }
1277         aStr.append("  </tr>\r\n");
1278     }
1279     aStr.append("</table>\r\n");
1280 }
1281 
WriteObjectGroup(OUStringBuffer & aStr,SdrObjGroup const * pObjectGroup,SdrOutliner * pOutliner,const Color & rBackgroundColor,bool bHeadLine)1282 void HtmlExport::WriteObjectGroup(OUStringBuffer& aStr, SdrObjGroup const * pObjectGroup, SdrOutliner* pOutliner,
1283                                   const Color& rBackgroundColor, bool bHeadLine)
1284 {
1285     SdrObjListIter aGroupIterator(pObjectGroup->GetSubList(), SdrIterMode::DeepNoGroups);
1286     while (aGroupIterator.IsMore())
1287     {
1288         SdrObject* pCurrentObject = aGroupIterator.Next();
1289         if (pCurrentObject->GetObjIdentifier() == OBJ_GRUP)
1290         {
1291             SdrObjGroup* pCurrentGroupObject = static_cast<SdrObjGroup*>(pCurrentObject);
1292             WriteObjectGroup(aStr, pCurrentGroupObject, pOutliner, rBackgroundColor, bHeadLine);
1293         }
1294         else
1295         {
1296             OutlinerParaObject* pOutlinerParagraphObject = pCurrentObject->GetOutlinerParaObject();
1297             if (pOutlinerParagraphObject != nullptr)
1298             {
1299                 WriteOutlinerParagraph(aStr, pOutliner, pOutlinerParagraphObject, rBackgroundColor, bHeadLine);
1300             }
1301         }
1302     }
1303 }
1304 
WriteOutlinerParagraph(OUStringBuffer & aStr,SdrOutliner * pOutliner,OutlinerParaObject const * pOutlinerParagraphObject,const Color & rBackgroundColor,bool bHeadLine)1305 void HtmlExport::WriteOutlinerParagraph(OUStringBuffer& aStr, SdrOutliner* pOutliner,
1306                                         OutlinerParaObject const * pOutlinerParagraphObject,
1307                                         const Color& rBackgroundColor, bool bHeadLine)
1308 {
1309     if (pOutlinerParagraphObject == nullptr)
1310         return;
1311 
1312     pOutliner->SetText(*pOutlinerParagraphObject);
1313 
1314     sal_Int32 nCount = pOutliner->GetParagraphCount();
1315 
1316 
1317     sal_Int16 nCurrentDepth = -1;
1318 
1319     for (sal_Int32 nIndex = 0; nIndex < nCount; nIndex++)
1320     {
1321         Paragraph* pParagraph = pOutliner->GetParagraph(nIndex);
1322         if(pParagraph == nullptr)
1323             continue;
1324 
1325         const sal_Int16 nDepth = static_cast<sal_uInt16>(pOutliner->GetDepth(nIndex));
1326         OUString aParaText = ParagraphToHTMLString(pOutliner, nIndex, rBackgroundColor);
1327 
1328         if (aParaText.isEmpty())
1329             continue;
1330 
1331         if (nDepth < 0)
1332         {
1333             OUString aTag = bHeadLine ? OUString("h2") : OUString("p");
1334             lclAppendStyle(aStr, aTag, getParagraphStyle(pOutliner, nIndex));
1335 
1336             aStr.append(aParaText);
1337             aStr.append("</" + aTag + ">\r\n");
1338         }
1339         else
1340         {
1341             while(nCurrentDepth < nDepth)
1342             {
1343                 aStr.append("<ul>\r\n");
1344                 nCurrentDepth++;
1345             }
1346             while(nCurrentDepth > nDepth)
1347             {
1348                 aStr.append("</ul>\r\n");
1349                 nCurrentDepth--;
1350             }
1351             lclAppendStyle(aStr, u"li", getParagraphStyle(pOutliner, nIndex));
1352             aStr.append(aParaText);
1353             aStr.append("</li>\r\n");
1354         }
1355     }
1356     while(nCurrentDepth >= 0)
1357     {
1358         aStr.append("</ul>\r\n");
1359         nCurrentDepth--;
1360     }
1361     pOutliner->Clear();
1362 }
1363 
1364 // creates an outliner text for a note page
CreateTextForNotesPage(SdrOutliner * pOutliner,SdPage * pPage,const Color & rBackgroundColor)1365 OUString HtmlExport::CreateTextForNotesPage( SdrOutliner* pOutliner,
1366                                            SdPage* pPage,
1367                                            const Color& rBackgroundColor )
1368 {
1369     OUStringBuffer aStr;
1370 
1371     SdrTextObj* pTO = static_cast<SdrTextObj*>(pPage->GetPresObj(PresObjKind::Notes));
1372 
1373     if (pTO && !pTO->IsEmptyPresObj())
1374     {
1375         OutlinerParaObject* pOPO = pTO->GetOutlinerParaObject();
1376         if (pOPO)
1377         {
1378             pOutliner->Clear();
1379             pOutliner->SetText( *pOPO );
1380 
1381             sal_Int32 nCount = pOutliner->GetParagraphCount();
1382             for (sal_Int32 nPara = 0; nPara < nCount; nPara++)
1383             {
1384                 lclAppendStyle(aStr, u"p", getParagraphStyle(pOutliner, nPara));
1385                 aStr.append(ParagraphToHTMLString(pOutliner, nPara, rBackgroundColor));
1386                 aStr.append("</p>\r\n");
1387             }
1388         }
1389     }
1390 
1391     return aStr.makeStringAndClear();
1392 }
1393 
1394 // converts a paragraph of the outliner to html
ParagraphToHTMLString(SdrOutliner const * pOutliner,sal_Int32 nPara,const Color & rBackgroundColor)1395 OUString HtmlExport::ParagraphToHTMLString( SdrOutliner const * pOutliner, sal_Int32 nPara, const Color& rBackgroundColor )
1396 {
1397     OUStringBuffer aStr;
1398 
1399     if(nullptr == pOutliner)
1400         return OUString();
1401 
1402     // TODO: MALTE!!!
1403     EditEngine& rEditEngine = *const_cast<EditEngine*>(&pOutliner->GetEditEngine());
1404     bool bOldUpdateMode = rEditEngine.GetUpdateMode();
1405     rEditEngine.SetUpdateMode(true);
1406 
1407     Paragraph* pPara = pOutliner->GetParagraph(nPara);
1408     if(nullptr == pPara)
1409         return OUString();
1410 
1411     HtmlState aState( (mbUserAttr || mbDocColors)  ? maTextColor : COL_BLACK );
1412     std::vector<sal_Int32> aPortionList;
1413     rEditEngine.GetPortions( nPara, aPortionList );
1414 
1415     sal_Int32 nPos1 = 0;
1416     for( sal_Int32 nPos2 : aPortionList )
1417     {
1418         ESelection aSelection( nPara, nPos1, nPara, nPos2);
1419 
1420         SfxItemSet aSet( rEditEngine.GetAttribs( aSelection ) );
1421 
1422         OUString aPortion(StringToHTMLString(rEditEngine.GetText( aSelection )));
1423 
1424         aStr.append(TextAttribToHTMLString( &aSet, &aState, rBackgroundColor ));
1425         aStr.append(aPortion);
1426 
1427         nPos1 = nPos2;
1428     }
1429     aStr.append(aState.Flush());
1430     rEditEngine.SetUpdateMode(bOldUpdateMode);
1431 
1432     return aStr.makeStringAndClear();
1433 }
1434 
1435 // Depending on the attributes of the specified set and the specified
1436 // HtmlState, it creates the needed html tags in order to get the
1437 // attributes
TextAttribToHTMLString(SfxItemSet const * pSet,HtmlState * pState,const Color & rBackgroundColor)1438 OUString HtmlExport::TextAttribToHTMLString( SfxItemSet const * pSet, HtmlState* pState, const Color& rBackgroundColor )
1439 {
1440     OUStringBuffer aStr;
1441 
1442     if(nullptr == pSet)
1443         return OUString();
1444 
1445     OUString aLink, aTarget;
1446     if ( pSet->GetItemState( EE_FEATURE_FIELD ) == SfxItemState::SET )
1447     {
1448         const SvxFieldItem* pItem = pSet->GetItem<SvxFieldItem>( EE_FEATURE_FIELD );
1449         if(pItem)
1450         {
1451             const SvxURLField* pURL = dynamic_cast<const SvxURLField*>( pItem->GetField() );
1452             if(pURL)
1453             {
1454                 aLink = pURL->GetURL();
1455                 aTarget = pURL->GetTargetFrame();
1456             }
1457         }
1458     }
1459 
1460     bool bTemp;
1461     OUString aTemp;
1462 
1463     if ( pSet->GetItemState( EE_CHAR_WEIGHT ) == SfxItemState::SET )
1464     {
1465         bTemp = pSet->Get( EE_CHAR_WEIGHT ).GetWeight() == WEIGHT_BOLD;
1466         aTemp = pState->SetWeight( bTemp );
1467         if( bTemp )
1468             aStr.insert(0, aTemp);
1469         else
1470             aStr.append(aTemp);
1471     }
1472 
1473     if ( pSet->GetItemState( EE_CHAR_UNDERLINE ) == SfxItemState::SET )
1474     {
1475         bTemp = pSet->Get( EE_CHAR_UNDERLINE ).GetLineStyle() != LINESTYLE_NONE;
1476         aTemp = pState->SetUnderline( bTemp );
1477         if( bTemp )
1478             aStr.insert(0, aTemp);
1479         else
1480             aStr.append(aTemp);
1481     }
1482 
1483     if ( pSet->GetItemState( EE_CHAR_STRIKEOUT ) == SfxItemState::SET )
1484     {
1485         bTemp = pSet->Get( EE_CHAR_STRIKEOUT ).GetStrikeout() != STRIKEOUT_NONE;
1486         aTemp = pState->SetStrikeout( bTemp );
1487         if( bTemp )
1488             aStr.insert(0, aTemp);
1489         else
1490             aStr.append(aTemp);
1491     }
1492 
1493     if ( pSet->GetItemState( EE_CHAR_ITALIC ) == SfxItemState::SET )
1494     {
1495         bTemp = pSet->Get( EE_CHAR_ITALIC ).GetPosture() != ITALIC_NONE;
1496         aTemp = pState->SetItalic( bTemp );
1497         if( bTemp )
1498             aStr.insert(0, aTemp);
1499         else
1500             aStr.append(aTemp);
1501     }
1502 
1503     if(mbDocColors)
1504     {
1505         if ( pSet->GetItemState( EE_CHAR_COLOR ) == SfxItemState::SET )
1506         {
1507             Color aTextColor = pSet->Get( EE_CHAR_COLOR ).GetValue();
1508             if( aTextColor == COL_AUTO )
1509             {
1510                 if( !rBackgroundColor.IsDark() )
1511                     aTextColor = COL_BLACK;
1512             }
1513             aStr.append(pState->SetColor( aTextColor ));
1514         }
1515     }
1516 
1517     if (!aLink.isEmpty())
1518         aStr.insert(0, pState->SetLink(aLink, aTarget));
1519     else
1520         aStr.append(pState->SetLink(aLink, aTarget));
1521 
1522     return aStr.makeStringAndClear();
1523 }
1524 
1525 // create HTML wrapper for picture files
CreateHtmlForPresPages()1526 bool HtmlExport::CreateHtmlForPresPages()
1527 {
1528     bool bOk = true;
1529 
1530     std::vector<SdrObject*> aClickableObjects;
1531 
1532     for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount && bOk; nSdPage++)
1533     {
1534         // find clickable objects (also on the master page) and put it in the
1535         // list. This in reverse order character order since in html the first
1536         // area is taken in the case they overlap.
1537         SdPage* pPage = maPages[ nSdPage ];
1538 
1539         if( mbDocColors )
1540         {
1541             SetDocColors( pPage );
1542         }
1543 
1544         bool    bMasterDone = false;
1545 
1546         while (!bMasterDone)
1547         {
1548             // sal_True = backwards
1549             SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups, true);
1550 
1551             SdrObject* pObject = aIter.Next();
1552             while (pObject)
1553             {
1554                 SdAnimationInfo* pInfo     = SdDrawDocument::GetAnimationInfo(pObject);
1555                 SvxIMapInfo*      pIMapInfo = SvxIMapInfo::GetIMapInfo(pObject);
1556 
1557                 if ((pInfo &&
1558                      (pInfo->meClickAction == presentation::ClickAction_BOOKMARK  ||
1559                       pInfo->meClickAction == presentation::ClickAction_DOCUMENT  ||
1560                       pInfo->meClickAction == presentation::ClickAction_PREVPAGE  ||
1561                       pInfo->meClickAction == presentation::ClickAction_NEXTPAGE  ||
1562                       pInfo->meClickAction == presentation::ClickAction_FIRSTPAGE ||
1563                       pInfo->meClickAction == presentation::ClickAction_LASTPAGE)) ||
1564                      pIMapInfo)
1565                 {
1566                     aClickableObjects.push_back(pObject);
1567                 }
1568 
1569                 pObject = aIter.Next();
1570             }
1571             // now to the master page or finishing
1572             if (!pPage->IsMasterPage())
1573                 pPage = static_cast<SdPage*>(&(pPage->TRG_GetMasterPage()));
1574             else
1575                 bMasterDone = true;
1576         }
1577 
1578         // HTML Head
1579         OUStringBuffer aStr(gaHTMLHeader);
1580         aStr.append(CreateMetaCharset());
1581         aStr.append("  <title>" + StringToHTMLString(maPageNames[nSdPage]) + "</title>\r\n");
1582 
1583         // insert timing information
1584         pPage = maPages[ nSdPage ];
1585         if( meMode == PUBLISH_KIOSK )
1586         {
1587             double fSecs = 0;
1588             bool bEndless = false;
1589             if( !mbAutoSlide )
1590             {
1591                 if( pPage->GetPresChange() != PresChange::Manual )
1592                 {
1593                     fSecs = pPage->GetTime();
1594                     bEndless = mpDoc->getPresentationSettings().mbEndless;
1595                 }
1596             }
1597             else
1598             {
1599                 fSecs = mfSlideDuration;
1600                 bEndless = mbEndless;
1601             }
1602 
1603             if( fSecs != 0 )
1604             {
1605                 if( nSdPage < (mnSdPageCount-1) || bEndless )
1606                 {
1607                     aStr.append("<meta http-equiv=\"refresh\" content=\"");
1608                     aStr.append(fSecs);
1609                     aStr.append("; URL=");
1610 
1611                     int nPage = nSdPage + 1;
1612                     if( nPage == mnSdPageCount )
1613                         nPage = 0;
1614 
1615                     aStr.append(maHTMLFiles[nPage]);
1616 
1617                     aStr.append("\">\r\n");
1618                 }
1619             }
1620         }
1621 
1622         aStr.append("</head>\r\n");
1623 
1624         // HTML Body
1625         aStr.append(CreateBodyTag());
1626 
1627         if( mbSlideSound && pPage->IsSoundOn() )
1628             aStr.append(InsertSound(pPage->GetSoundFile()));
1629 
1630         // navigation bar
1631         if(!mbFrames )
1632             aStr.append(CreateNavBar(nSdPage, false));
1633         // Image
1634         aStr.append("<center>");
1635         aStr.append("<img src=\"");
1636         aStr.append(maImageFiles[nSdPage]);
1637         aStr.append("\" alt=\"\"");
1638 
1639         if (!aClickableObjects.empty())
1640             aStr.append(" USEMAP=\"#map0\"");
1641 
1642         aStr.append("></center>\r\n");
1643 
1644         // notes
1645         if(mbNotes && !mbFrames)
1646         {
1647             SdrOutliner* pOutliner = mpDoc->GetInternalOutliner();
1648             SdPage* pNotesPage = maNotesPages[ nSdPage ];
1649             OUString aNotesStr( CreateTextForNotesPage( pOutliner, pNotesPage, maBackColor) );
1650             pOutliner->Clear();
1651 
1652             if (!aNotesStr.isEmpty())
1653             {
1654                 aStr.append("<h3>");
1655                 aStr.append(RESTOHTML(STR_HTMLEXP_NOTES));
1656                 aStr.append(":</h3><br>\r\n\r\n<p>");
1657 
1658                 aStr.append(aNotesStr);
1659                 aStr.append("\r\n</p>\r\n");
1660             }
1661         }
1662 
1663         // create Imagemap if necessary
1664         if (!aClickableObjects.empty())
1665         {
1666             aStr.append("<map name=\"map0\">\r\n");
1667 
1668             for (SdrObject* pObject : aClickableObjects)
1669             {
1670                 SdAnimationInfo* pInfo     = SdDrawDocument::GetAnimationInfo(pObject);
1671                 SvxIMapInfo*      pIMapInfo = SvxIMapInfo::GetIMapInfo(pObject);
1672 
1673                 ::tools::Rectangle aRect(pObject->GetCurrentBoundRect());
1674                 Point     aLogPos(aRect.TopLeft());
1675                 bool      bIsSquare = aRect.GetWidth() == aRect.GetHeight();
1676 
1677                 sal_uLong nPageWidth = pPage->GetSize().Width() - pPage->GetLeftBorder() -
1678                                    pPage->GetRightBorder();
1679 
1680                 // BoundRect is relative to the physical page origin, not the
1681                 // origin of ordinates
1682                 aRect.Move(-pPage->GetLeftBorder(), -pPage->GetUpperBorder());
1683 
1684                 double fLogicToPixel = static_cast<double>(mnWidthPixel) / nPageWidth;
1685                 aRect.SetLeft( static_cast<tools::Long>(aRect.Left() * fLogicToPixel) );
1686                 aRect.SetTop( static_cast<tools::Long>(aRect.Top() * fLogicToPixel) );
1687                 aRect.SetRight( static_cast<tools::Long>(aRect.Right() * fLogicToPixel) );
1688                 aRect.SetBottom( static_cast<tools::Long>(aRect.Bottom() * fLogicToPixel) );
1689                 tools::Long nRadius = aRect.GetWidth() / 2;
1690 
1691                 /**
1692                     insert areas into Imagemap of the object, if the object has
1693                     such an Imagemap
1694                 */
1695                 if (pIMapInfo)
1696                 {
1697                     const ImageMap& rIMap = pIMapInfo->GetImageMap();
1698                     sal_uInt16 nAreaCount = rIMap.GetIMapObjectCount();
1699                     for (sal_uInt16 nArea = 0; nArea < nAreaCount; nArea++)
1700                     {
1701                         IMapObject* pArea = rIMap.GetIMapObject(nArea);
1702                         IMapObjectType nType = pArea->GetType();
1703                         OUString aURL( pArea->GetURL() );
1704 
1705                         // if necessary, convert page and object names into the
1706                         // corresponding names of the html file
1707                         bool        bIsMasterPage;
1708                         sal_uInt16  nPgNum = mpDoc->GetPageByName( aURL, bIsMasterPage );
1709 
1710                         if (nPgNum == SDRPAGE_NOTFOUND)
1711                         {
1712                             // is the bookmark an object?
1713                             SdrObject* pObj = mpDoc->GetObj( aURL );
1714                             if (pObj)
1715                                 nPgNum = pObj->getSdrPageFromSdrObject()->GetPageNum();
1716                         }
1717                         if (nPgNum != SDRPAGE_NOTFOUND)
1718                         {
1719                             nPgNum = (nPgNum - 1) / 2;  // SdrPageNum --> SdPageNum
1720                             aURL = CreatePageURL(nPgNum);
1721                         }
1722 
1723                         switch(nType)
1724                         {
1725                             case IMapObjectType::Rectangle:
1726                             {
1727                                 ::tools::Rectangle aArea(static_cast<IMapRectangleObject*>(pArea)->
1728                                                  GetRectangle(false));
1729 
1730                                 // conversion into pixel coordinates
1731                                 aArea.Move(aLogPos.X() - pPage->GetLeftBorder(),
1732                                            aLogPos.Y() - pPage->GetUpperBorder());
1733                                 aArea.SetLeft( static_cast<tools::Long>(aArea.Left() * fLogicToPixel) );
1734                                 aArea.SetTop( static_cast<tools::Long>(aArea.Top() * fLogicToPixel) );
1735                                 aArea.SetRight( static_cast<tools::Long>(aArea.Right() * fLogicToPixel) );
1736                                 aArea.SetBottom( static_cast<tools::Long>(aArea.Bottom() * fLogicToPixel) );
1737 
1738                                 aStr.append(CreateHTMLRectArea(aArea, aURL));
1739                             }
1740                             break;
1741 
1742                             case IMapObjectType::Circle:
1743                             {
1744                                 Point aCenter(static_cast<IMapCircleObject*>(pArea)->
1745                                                  GetCenter(false));
1746                                 aCenter += Point(aLogPos.X() - pPage->GetLeftBorder(),
1747                                                  aLogPos.Y() - pPage->GetUpperBorder());
1748                                 aCenter.setX( static_cast<tools::Long>(aCenter.X() * fLogicToPixel) );
1749                                 aCenter.setY( static_cast<tools::Long>(aCenter.Y() * fLogicToPixel) );
1750 
1751                                 sal_uLong nCircleRadius = static_cast<IMapCircleObject*>(pArea)->
1752                                                  GetRadius(false);
1753                                 nCircleRadius = static_cast<sal_uLong>(nCircleRadius * fLogicToPixel);
1754                                 aStr.append(CreateHTMLCircleArea(nCircleRadius,
1755                                                             aCenter.X(), aCenter.Y(),
1756                                                             aURL));
1757                             }
1758                             break;
1759 
1760                             case IMapObjectType::Polygon:
1761                             {
1762                                 tools::Polygon aArea(static_cast<IMapPolygonObject*>(pArea)->GetPolygon(false));
1763                                 aStr.append(CreateHTMLPolygonArea(::basegfx::B2DPolyPolygon(aArea.getB2DPolygon()),
1764                                                                   Size(aLogPos.X() - pPage->GetLeftBorder(),
1765                                                                        aLogPos.Y() - pPage->GetUpperBorder()),
1766                                                                   fLogicToPixel, aURL));
1767                             }
1768                             break;
1769 
1770                             default:
1771                             {
1772                                 SAL_INFO("sd", "unknown IMapObjectType");
1773                             }
1774                             break;
1775                         }
1776                     }
1777                 }
1778 
1779                 /**
1780                     if there is a presentation::ClickAction, determine bookmark
1781                     and create area for the whole object
1782                 */
1783                 if( pInfo )
1784                 {
1785                     OUString aHRef;
1786                     presentation::ClickAction eClickAction = pInfo->meClickAction;
1787 
1788                     switch( eClickAction )
1789                     {
1790                         case presentation::ClickAction_BOOKMARK:
1791                         {
1792                             bool        bIsMasterPage;
1793                             sal_uInt16  nPgNum = mpDoc->GetPageByName( pInfo->GetBookmark(), bIsMasterPage );
1794 
1795                             if( nPgNum == SDRPAGE_NOTFOUND )
1796                             {
1797                                 // is the bookmark an object?
1798                                 SdrObject* pObj = mpDoc->GetObj(pInfo->GetBookmark());
1799                                 if (pObj)
1800                                     nPgNum = pObj->getSdrPageFromSdrObject()->GetPageNum();
1801                             }
1802 
1803                             if( SDRPAGE_NOTFOUND != nPgNum )
1804                                 aHRef = CreatePageURL(( nPgNum - 1 ) / 2 );
1805                         }
1806                         break;
1807 
1808                         case presentation::ClickAction_DOCUMENT:
1809                             aHRef = pInfo->GetBookmark();
1810                         break;
1811 
1812                         case presentation::ClickAction_PREVPAGE:
1813                         {
1814                             sal_uLong nPage;
1815 
1816                             if (nSdPage == 0)
1817                                 nPage = 0;
1818                             else
1819                                 nPage = nSdPage - 1;
1820 
1821                             aHRef = CreatePageURL( static_cast<sal_uInt16>(nPage));
1822                         }
1823                         break;
1824 
1825                         case presentation::ClickAction_NEXTPAGE:
1826                         {
1827                             sal_uLong nPage;
1828                             if (nSdPage == mnSdPageCount - 1)
1829                                 nPage = mnSdPageCount - 1;
1830                             else
1831                                 nPage = nSdPage + 1;
1832 
1833                             aHRef = CreatePageURL( static_cast<sal_uInt16>(nPage));
1834                         }
1835                         break;
1836 
1837                         case presentation::ClickAction_FIRSTPAGE:
1838                             aHRef = CreatePageURL(0);
1839                         break;
1840 
1841                         case presentation::ClickAction_LASTPAGE:
1842                             aHRef = CreatePageURL(mnSdPageCount - 1);
1843                         break;
1844 
1845                         default:
1846                             break;
1847                     }
1848 
1849                     // and now the areas
1850                     if (!aHRef.isEmpty())
1851                     {
1852                         // a circle?
1853                         if (pObject->GetObjInventor() == SdrInventor::Default &&
1854                             pObject->GetObjIdentifier() == OBJ_CIRC  &&
1855                             bIsSquare )
1856                         {
1857                             aStr.append(CreateHTMLCircleArea(aRect.GetWidth() / 2,
1858                                                     aRect.Left() + nRadius,
1859                                                     aRect.Top() + nRadius,
1860                                                     aHRef));
1861                         }
1862                         // a polygon?
1863                         else if (pObject->GetObjInventor() == SdrInventor::Default &&
1864                                  (pObject->GetObjIdentifier() == OBJ_PATHLINE ||
1865                                   pObject->GetObjIdentifier() == OBJ_PLIN ||
1866                                   pObject->GetObjIdentifier() == OBJ_POLY))
1867                         {
1868                             aStr.append(CreateHTMLPolygonArea(static_cast<SdrPathObj*>(pObject)->GetPathPoly(), Size(-pPage->GetLeftBorder(), -pPage->GetUpperBorder()), fLogicToPixel, aHRef));
1869                         }
1870                         // something completely different: use the BoundRect
1871                         else
1872                         {
1873                             aStr.append(CreateHTMLRectArea(aRect, aHRef));
1874                         }
1875 
1876                     }
1877                 }
1878             }
1879 
1880             aStr.append("</map>\r\n");
1881         }
1882         aClickableObjects.clear();
1883 
1884         aStr.append("</body>\r\n</html>");
1885 
1886         bOk = WriteHtml(maHTMLFiles[nSdPage], false, aStr.makeStringAndClear());
1887 
1888         if (mpProgress)
1889             mpProgress->SetState(++mnPagesWritten);
1890     }
1891 
1892     return bOk;
1893 }
1894 
1895 // create overview pages
CreateContentPage()1896 bool HtmlExport::CreateContentPage()
1897 {
1898     if( mbDocColors )
1899         SetDocColors();
1900 
1901     // html head
1902     OUStringBuffer aStr(gaHTMLHeader);
1903     aStr.append(CreateMetaCharset());
1904     aStr.append("  <title>");
1905     aStr.append(StringToHTMLString(maPageNames[0]));
1906     aStr.append("</title>\r\n</head>\r\n");
1907     aStr.append(CreateBodyTag());
1908 
1909     // page head
1910     aStr.append("<center>\r\n");
1911 
1912     if(mbHeader)
1913     {
1914         aStr.append("<h1>");
1915         aStr.append(getDocumentTitle());
1916         aStr.append("</h1><br>\r\n");
1917     }
1918 
1919     aStr.append("<h2>");
1920 
1921     // Solaris compiler bug workaround
1922     if( mbFrames )
1923         aStr.append(CreateLink(maFramePage,
1924                                RESTOHTML(STR_HTMLEXP_CLICKSTART)));
1925     else
1926         aStr.append(CreateLink(StringToHTMLString(maHTMLFiles[0]),
1927                                RESTOHTML(STR_HTMLEXP_CLICKSTART)));
1928 
1929     aStr.append("</h2>\r\n</center>\r\n");
1930 
1931     aStr.append("<center><table width=\"90%\"><tr>\r\n");
1932 
1933     // table of content
1934     aStr.append("<td valign=\"top\" align=\"left\" width=\"25%\">\r\n");
1935     aStr.append("<h3>");
1936     aStr.append(RESTOHTML(STR_HTMLEXP_CONTENTS));
1937     aStr.append("</h3>");
1938 
1939     for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
1940     {
1941         OUString aPageName = maPageNames[nSdPage];
1942         aStr.append("<div align=\"left\">");
1943         if(mbFrames)
1944             aStr.append(StringToHTMLString(aPageName));
1945         else
1946             aStr.append(CreateLink(maHTMLFiles[nSdPage], aPageName));
1947         aStr.append("</div>\r\n");
1948     }
1949     aStr.append("</td>\r\n");
1950 
1951     // document information
1952     aStr.append("<td valign=\"top\" align=\"left\" width=\"75%\">\r\n");
1953 
1954     if (!maAuthor.isEmpty())
1955     {
1956         aStr.append("<p><strong>");
1957         aStr.append(RESTOHTML(STR_HTMLEXP_AUTHOR));
1958         aStr.append(":</strong> ");
1959         aStr.append(StringToHTMLString(maAuthor));
1960         aStr.append("</p>\r\n");
1961     }
1962 
1963     if (!maEMail.isEmpty())
1964     {
1965         aStr.append("<p><strong>");
1966         aStr.append(RESTOHTML(STR_HTMLEXP_EMAIL));
1967         aStr.append(":</strong> <a href=\"mailto:");
1968         aStr.append(maEMail);
1969         aStr.append("\">");
1970         aStr.append(StringToHTMLString(maEMail));
1971         aStr.append("</a></p>\r\n");
1972     }
1973 
1974     if (!maHomePage.isEmpty())
1975     {
1976         aStr.append("<p><strong>");
1977         aStr.append(RESTOHTML(STR_HTMLEXP_HOMEPAGE));
1978         aStr.append(":</strong> <a href=\"");
1979         aStr.append(maHomePage);
1980         aStr.append("\">");
1981         aStr.append(StringToHTMLString(maHomePage));
1982         aStr.append("</a> </p>\r\n");
1983     }
1984 
1985     if (!maInfo.isEmpty())
1986     {
1987         aStr.append("<p><strong>");
1988         aStr.append(RESTOHTML(STR_HTMLEXP_INFO));
1989         aStr.append(":</strong><br>\r\n");
1990         aStr.append(StringToHTMLString(maInfo));
1991         aStr.append("</p>\r\n");
1992     }
1993 
1994     if(mbDownload)
1995     {
1996         aStr.append("<p><a href=\"");
1997         aStr.append(maDocFileName);
1998         aStr.append("\">");
1999         aStr.append(RESTOHTML(STR_HTMLEXP_DOWNLOAD));
2000         aStr.append("</a></p>\r\n");
2001     }
2002 
2003     for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
2004     {
2005         OUString aText(
2006             "<img src=\"" +
2007             maThumbnailFiles[nSdPage] +
2008             "\" width=\"256\" height=\"192\" alt=\"" +
2009             StringToHTMLString(maPageNames[nSdPage]) +
2010             "\">");
2011 
2012         aStr.append(CreateLink(maHTMLFiles[nSdPage], aText));
2013         aStr.append("\r\n");
2014     }
2015 
2016     aStr.append("</td></tr></table></center>\r\n");
2017 
2018     aStr.append("</body>\r\n</html>");
2019 
2020     bool bOk = WriteHtml(maIndex, false, aStr.makeStringAndClear());
2021 
2022     if (mpProgress)
2023         mpProgress->SetState(++mnPagesWritten);
2024 
2025     return bOk;
2026 }
2027 
2028 // create note pages (for frames)
2029 
CreateNotesPages()2030 bool HtmlExport::CreateNotesPages()
2031 {
2032     bool bOk = true;
2033 
2034     SdrOutliner* pOutliner = mpDoc->GetInternalOutliner();
2035     for( sal_uInt16 nSdPage = 0; bOk && nSdPage < mnSdPageCount; nSdPage++ )
2036     {
2037         SdPage* pPage = maNotesPages[nSdPage];
2038         if( mbDocColors )
2039             SetDocColors( pPage );
2040 
2041         // Html head
2042         OUStringBuffer aStr(gaHTMLHeader);
2043         aStr.append(CreateMetaCharset());
2044         aStr.append("  <title>");
2045         aStr.append(StringToHTMLString(maPageNames[0]));
2046         aStr.append("</title>\r\n</head>\r\n");
2047         aStr.append(CreateBodyTag());
2048 
2049         if(pPage)
2050             aStr.append(CreateTextForNotesPage( pOutliner, pPage, maBackColor ));
2051 
2052         aStr.append("</body>\r\n</html>");
2053 
2054         OUString aFileName("note" + OUString::number(nSdPage));
2055         bOk = WriteHtml(aFileName, true, aStr.makeStringAndClear());
2056 
2057         if (mpProgress)
2058             mpProgress->SetState(++mnPagesWritten);
2059     }
2060 
2061     pOutliner->Clear();
2062 
2063     return bOk;
2064 }
2065 
2066 // create outline pages (for frames)
2067 
CreateOutlinePages()2068 bool HtmlExport::CreateOutlinePages()
2069 {
2070     bool bOk = true;
2071 
2072     if( mbDocColors )
2073     {
2074         SetDocColors();
2075     }
2076 
2077     // page 0 will be the closed outline, page 1 the opened
2078     for (sal_Int32 nPage = 0; nPage < (mbImpress?2:1) && bOk; ++nPage)
2079     {
2080         // Html head
2081         OUStringBuffer aStr(gaHTMLHeader);
2082         aStr.append(CreateMetaCharset());
2083         aStr.append("  <title>");
2084         aStr.append(StringToHTMLString(maPageNames[0]));
2085         aStr.append("</title>\r\n</head>\r\n");
2086         aStr.append(CreateBodyTag());
2087 
2088         SdrOutliner* pOutliner = mpDoc->GetInternalOutliner();
2089         for(sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
2090         {
2091             SdPage* pPage = maPages[ nSdPage ];
2092 
2093             aStr.append("<div align=\"left\">");
2094             OUString aLink("JavaScript:parent.NavigateAbs(" +
2095                 OUString::number(nSdPage) + ")");
2096 
2097             OUString aTitle = CreateTextForTitle(pOutliner, pPage, maBackColor);
2098             if (aTitle.isEmpty())
2099                 aTitle = maPageNames[nSdPage];
2100 
2101             lclAppendStyle(aStr, u"p", getParagraphStyle(pOutliner, 0));
2102             aStr.append(CreateLink(aLink, aTitle));
2103             aStr.append("</p>");
2104 
2105             if(nPage==1)
2106             {
2107                 aStr.append(CreateTextForPage( pOutliner, pPage, false, maBackColor ));
2108             }
2109             aStr.append("</div>\r\n");
2110         }
2111         pOutliner->Clear();
2112 
2113         aStr.append("</body>\r\n</html>");
2114 
2115         OUString aFileName("outline" + OUString::number(nPage));
2116         bOk = WriteHtml(aFileName, true, aStr.makeStringAndClear());
2117 
2118         if (mpProgress)
2119             mpProgress->SetState(++mnPagesWritten);
2120     }
2121 
2122     return bOk;
2123 }
2124 
2125 // set file name
CreateFileNames()2126 void HtmlExport::CreateFileNames()
2127 {
2128     // create lists with new file names
2129     maHTMLFiles.resize(mnSdPageCount);
2130     maImageFiles.resize(mnSdPageCount);
2131     maThumbnailFiles.resize(mnSdPageCount);
2132     maPageNames.resize(mnSdPageCount);
2133     maTextFiles.resize(mnSdPageCount);
2134 
2135     mbHeader = false;   // headline on overview page?
2136 
2137     for (sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
2138     {
2139         OUString aHTMLFileName;
2140         if(nSdPage == 0 && !mbContentsPage && !mbFrames )
2141             aHTMLFileName = maIndex;
2142         else
2143         {
2144             aHTMLFileName = "img" + OUString::number(nSdPage) + gaHTMLExtension;
2145         }
2146 
2147         maHTMLFiles[nSdPage] = aHTMLFileName;
2148 
2149         OUString aImageFileName = "img" + OUString::number(nSdPage);
2150         if( meFormat==FORMAT_GIF )
2151             aImageFileName += ".gif";
2152         else if( meFormat==FORMAT_JPG )
2153             aImageFileName += ".jpg";
2154         else
2155             aImageFileName += ".png";
2156 
2157         maImageFiles[nSdPage] = aImageFileName;
2158 
2159         OUString aThumbnailFileName = "thumb" + OUString::number(nSdPage);
2160         if( meFormat!=FORMAT_JPG )
2161             aThumbnailFileName += ".png";
2162         else
2163             aThumbnailFileName += ".jpg";
2164 
2165         maThumbnailFiles[nSdPage] = aThumbnailFileName;
2166 
2167         maTextFiles[nSdPage] = "text" + OUString::number(nSdPage) + gaHTMLExtension;
2168 
2169         SdPage* pSdPage = maPages[ nSdPage ];
2170 
2171         // get slide title from page name
2172         maPageNames[nSdPage] = pSdPage->GetName();
2173     }
2174 
2175     if(!mbContentsPage && mbFrames)
2176         maFramePage = maIndex;
2177     else
2178     {
2179         maFramePage = "siframes" + gaHTMLExtension;
2180     }
2181 }
2182 
getDocumentTitle()2183 OUString const & HtmlExport::getDocumentTitle()
2184 {
2185     // check for a title object in this page, if it's the first
2186     // title it becomes this documents title for the content
2187     // page
2188     if( !mbHeader )
2189     {
2190         if(mbImpress)
2191         {
2192             // if there is a non-empty title object, use their first passage
2193             // as page title
2194             SdPage* pSdPage = mpDoc->GetSdPage(0, PageKind::Standard);
2195             SdrObject* pTitleObj = pSdPage->GetPresObj(PresObjKind::Title);
2196             if (pTitleObj && !pTitleObj->IsEmptyPresObj())
2197             {
2198                 OutlinerParaObject* pParaObject = pTitleObj->GetOutlinerParaObject();
2199                 if (pParaObject)
2200                 {
2201                     const EditTextObject& rEditTextObject =
2202                         pParaObject->GetTextObject();
2203                     OUString aTest(rEditTextObject.GetText(0));
2204                     if (!aTest.isEmpty())
2205                         mDocTitle = aTest;
2206                 }
2207             }
2208 
2209             mDocTitle = mDocTitle.replace(0xff, ' ');
2210         }
2211 
2212         if (mDocTitle.isEmpty())
2213         {
2214             mDocTitle = maDocFileName;
2215             sal_Int32 nDot = mDocTitle.indexOf('.');
2216             if (nDot > 0)
2217                 mDocTitle = mDocTitle.copy(0, nDot);
2218         }
2219         mbHeader = true;
2220     }
2221 
2222     return mDocTitle;
2223 }
2224 
2225 constexpr OUStringLiteral JS_NavigateAbs =
2226     u"function NavigateAbs( nPage )\r\n"
2227     "{\r\n"
2228     "  frames[\"show\"].location.href = \"img\" + nPage + \".$EXT\";\r\n"
2229     "  //frames[\"notes\"].location.href = \"note\" + nPage + \".$EXT\";\r\n"
2230     "  nCurrentPage = nPage;\r\n"
2231     "  if(nCurrentPage==0)\r\n"
2232     "  {\r\n"
2233     "    frames[\"navbar1\"].location.href = \"navbar0.$EXT\";\r\n"
2234     "  }\r\n"
2235     "  else if(nCurrentPage==nPageCount-1)\r\n"
2236     "  {\r\n"
2237     "    frames[\"navbar1\"].location.href = \"navbar2.$EXT\";\r\n"
2238     "  }\r\n"
2239     "  else\r\n"
2240     "  {\r\n"
2241     "    frames[\"navbar1\"].location.href = \"navbar1.$EXT\";\r\n"
2242     "  }\r\n"
2243     "}\r\n\r\n";
2244 
2245 constexpr OUStringLiteral JS_NavigateRel =
2246     u"function NavigateRel( nDelta )\r\n"
2247     "{\r\n"
2248     "  var nPage = parseInt(nCurrentPage) + parseInt(nDelta);\r\n"
2249     "  if( (nPage >= 0) && (nPage < nPageCount) )\r\n"
2250     "  {\r\n"
2251     "    NavigateAbs( nPage );\r\n"
2252     "  }\r\n"
2253     "}\r\n\r\n";
2254 
2255 constexpr OUStringLiteral JS_ExpandOutline =
2256     u"function ExpandOutline()\r\n"
2257     "{\r\n"
2258     "  frames[\"navbar2\"].location.href = \"navbar4.$EXT\";\r\n"
2259     "  frames[\"outline\"].location.href = \"outline1.$EXT\";\r\n"
2260     "}\r\n\r\n";
2261 
2262 constexpr OUStringLiteral JS_CollapseOutline =
2263     u"function CollapseOutline()\r\n"
2264     "{\r\n"
2265     "  frames[\"navbar2\"].location.href = \"navbar3.$EXT\";\r\n"
2266     "  frames[\"outline\"].location.href = \"outline0.$EXT\";\r\n"
2267     "}\r\n\r\n";
2268 
2269 // create page with the frames
2270 
CreateFrames()2271 bool HtmlExport::CreateFrames()
2272 {
2273     OUString aTmp;
2274     OUStringBuffer aStr(
2275         "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Frameset//EN\"\r\n"
2276         "    \"http://www.w3.org/TR/html4/frameset.dtd\">\r\n"
2277         "<html>\r\n<head>\r\n");
2278 
2279     aStr.append(CreateMetaCharset());
2280     aStr.append("  <title>");
2281     aStr.append(StringToHTMLString(maPageNames[0]));
2282     aStr.append("</title>\r\n");
2283 
2284     aStr.append("<script type=\"text/javascript\">\r\n<!--\r\n");
2285 
2286     aStr.append("var nCurrentPage = 0;\r\nvar nPageCount = ");
2287     aStr.append(static_cast<sal_Int32>(mnSdPageCount));
2288     aStr.append(";\r\n\r\n");
2289 
2290     OUString aFunction = JS_NavigateAbs;
2291 
2292     if(mbNotes)
2293     {
2294         aFunction = aFunction.replaceAll("//", "");
2295     }
2296 
2297     // substitute HTML file extension
2298     OUString aPlaceHolder(".$EXT");
2299     aFunction = aFunction.replaceAll(aPlaceHolder, gaHTMLExtension);
2300     aStr.append(aFunction);
2301 
2302     aTmp = JS_NavigateRel;
2303     aTmp = aTmp.replaceAll(aPlaceHolder, gaHTMLExtension);
2304     aStr.append(aTmp);
2305 
2306     if(mbImpress)
2307     {
2308         aTmp = JS_ExpandOutline;
2309         aTmp = aTmp.replaceAll(aPlaceHolder, gaHTMLExtension);
2310         aStr.append(aTmp);
2311 
2312         aTmp = JS_CollapseOutline;
2313         aTmp = aTmp.replaceAll(aPlaceHolder, gaHTMLExtension);
2314         aStr.append(aTmp);
2315     }
2316     aStr.append("// -->\r\n</script>\r\n");
2317 
2318     aStr.append("</head>\r\n");
2319 
2320     aStr.append("<frameset cols=\"*,");
2321     aStr.append(static_cast<sal_Int32>(mnWidthPixel + 16));
2322     aStr.append("\">\r\n");
2323     if(mbImpress)
2324     {
2325         aStr.append("  <frameset rows=\"42,*\">\r\n");
2326         aStr.append("    <frame src=\"navbar3");
2327         aStr.append(gaHTMLExtension);
2328         aStr.append("\" name=\"navbar2\" marginwidth=\"4\" marginheight=\"4\" scrolling=\"no\">\r\n");
2329     }
2330     aStr.append("    <frame src=\"outline0");
2331     aStr.append(gaHTMLExtension);
2332     aStr.append("\" name=\"outline\">\r\n");
2333     if(mbImpress)
2334         aStr.append("  </frameset>\r\n");
2335 
2336     if(mbNotes)
2337     {
2338         aStr.append("  <frameset rows=\"42,");
2339         aStr.append(static_cast<sal_Int32>(static_cast<double>(mnWidthPixel) * 0.75) + 16);
2340         aStr.append(",*\">\r\n");
2341     }
2342     else
2343         aStr.append("  <frameset rows=\"42,*\">\r\n");
2344 
2345     aStr.append("    <frame src=\"navbar0");
2346     aStr.append(gaHTMLExtension);
2347     aStr.append("\" name=\"navbar1\" marginwidth=\"4\" marginheight=\"4\" scrolling=\"no\">\r\n");
2348 
2349     aStr.append("    <frame src=\"");
2350     aStr.append(maHTMLFiles[0]);
2351     aStr.append("\" name=\"show\" marginwidth=\"4\" marginheight=\"4\">\r\n");
2352 
2353     if(mbNotes)
2354     {
2355         aStr.append("    <frame src=\"note0");
2356         aStr.append(gaHTMLExtension);
2357         aStr.append("\" name=\"notes\">\r\n");
2358     }
2359     aStr.append("  </frameset>\r\n");
2360 
2361     aStr.append("<noframes>\r\n");
2362     aStr.append(CreateBodyTag());
2363     aStr.append(RESTOHTML(STR_HTMLEXP_NOFRAMES));
2364     aStr.append("\r\n</noframes>\r\n</frameset>\r\n</html>");
2365 
2366     bool bOk = WriteHtml(maFramePage, false, aStr.makeStringAndClear());
2367 
2368     if (mpProgress)
2369         mpProgress->SetState(++mnPagesWritten);
2370 
2371     return bOk;
2372 }
2373 
2374 // create button bar for standard
2375 // we create the following html files
2376 // navbar0.htm navigation bar graphic for the first page
2377 // navbar1.htm navigation bar graphic for the second until second last page
2378 // navbar2.htm navigation bar graphic for the last page
2379 // navbar3.htm navigation outline closed
2380 // navbar4.htm navigation outline open
CreateNavBarFrames()2381 bool HtmlExport::CreateNavBarFrames()
2382 {
2383     bool bOk = true;
2384     OUString aButton;
2385 
2386     if( mbDocColors )
2387     {
2388         SetDocColors();
2389         maBackColor = maFirstPageColor;
2390     }
2391 
2392     for( int nFile = 0; nFile < 3 && bOk; nFile++ )
2393     {
2394         OUStringBuffer aStr(gaHTMLHeader);
2395         aStr.append(CreateMetaCharset());
2396         aStr.append("  <title>");
2397         aStr.append(StringToHTMLString(maPageNames[0]));
2398         aStr.append("</title>\r\n</head>\r\n");
2399         aStr.append(CreateBodyTag());
2400         aStr.append("<center>\r\n");
2401 
2402         // first page
2403         aButton = SdResId(STR_HTMLEXP_FIRSTPAGE);
2404         if(mnButtonThema != -1)
2405             aButton = CreateImage(GetButtonName(nFile == 0 || mnSdPageCount == 1 ? BTN_FIRST_0 : BTN_FIRST_1),
2406                                   aButton);
2407 
2408         if(nFile != 0 && mnSdPageCount > 1)
2409             aButton = CreateLink(u"JavaScript:parent.NavigateAbs(0)", aButton);
2410 
2411         aStr.append(aButton);
2412         aStr.append("\r\n");
2413 
2414         // to the previous page
2415         aButton = SdResId(STR_PUBLISH_BACK);
2416         if(mnButtonThema != -1)
2417             aButton = CreateImage(GetButtonName(nFile == 0 || mnSdPageCount == 1?
2418                                     BTN_PREV_0:BTN_PREV_1),
2419                                   aButton);
2420 
2421         if(nFile != 0 && mnSdPageCount > 1)
2422             aButton = CreateLink(u"JavaScript:parent.NavigateRel(-1)", aButton);
2423 
2424         aStr.append(aButton);
2425         aStr.append("\r\n");
2426 
2427         // to the next page
2428         aButton = SdResId(STR_PUBLISH_NEXT);
2429         if(mnButtonThema != -1)
2430             aButton = CreateImage(GetButtonName(nFile ==2 || mnSdPageCount == 1?
2431                                     BTN_NEXT_0:BTN_NEXT_1),
2432                                   aButton);
2433 
2434         if(nFile != 2 && mnSdPageCount > 1)
2435             aButton = CreateLink(u"JavaScript:parent.NavigateRel(1)", aButton);
2436 
2437         aStr.append(aButton);
2438         aStr.append("\r\n");
2439 
2440         // to the last page
2441         aButton = SdResId(STR_HTMLEXP_LASTPAGE);
2442         if(mnButtonThema != -1)
2443             aButton = CreateImage(GetButtonName(nFile ==2 || mnSdPageCount == 1?
2444                                       BTN_LAST_0:BTN_LAST_1),
2445                                   aButton);
2446 
2447         if(nFile != 2 && mnSdPageCount > 1)
2448         {
2449             OUString aLink("JavaScript:parent.NavigateAbs(" +
2450                 OUString::number(mnSdPageCount-1) + ")");
2451 
2452             aButton = CreateLink(aLink, aButton);
2453         }
2454 
2455         aStr.append(aButton);
2456         aStr.append("\r\n");
2457 
2458         // content
2459         if (mbContentsPage)
2460         {
2461             aButton = SdResId(STR_PUBLISH_OUTLINE);
2462             if(mnButtonThema != -1)
2463                 aButton = CreateImage(GetButtonName(BTN_INDEX), aButton);
2464 
2465             // to the overview
2466             aStr.append(CreateLink(maIndex, aButton, u"_top"));
2467             aStr.append("\r\n");
2468         }
2469 
2470         // text mode
2471         if(mbImpress)
2472         {
2473             aButton = SdResId(STR_HTMLEXP_SETTEXT);
2474             if(mnButtonThema != -1)
2475                 aButton = CreateImage(GetButtonName(BTN_TEXT), aButton);
2476 
2477             OUString aText0("text0" + gaHTMLExtension);
2478             aStr.append(CreateLink(aText0, aButton, u"_top"));
2479             aStr.append("\r\n");
2480         }
2481 
2482         // and finished...
2483         aStr.append("</center>\r\n");
2484         aStr.append("</body>\r\n</html>");
2485 
2486         OUString aFileName("navbar" + OUString::number(nFile));
2487 
2488         bOk = WriteHtml(aFileName, true, aStr.makeStringAndClear());
2489 
2490         if (mpProgress)
2491             mpProgress->SetState(++mnPagesWritten);
2492     }
2493 
2494     // the navigation bar outliner closed...
2495     if(bOk)
2496     {
2497         OUStringBuffer aStr(gaHTMLHeader);
2498         aStr.append(CreateMetaCharset());
2499         aStr.append("  <title>");
2500         aStr.append(StringToHTMLString(maPageNames[0]));
2501         aStr.append("</title>\r\n</head>\r\n");
2502         aStr.append(CreateBodyTag());
2503 
2504         aButton = SdResId(STR_HTMLEXP_OUTLINE);
2505         if(mnButtonThema != -1)
2506             aButton = CreateImage(GetButtonName(BTN_MORE), aButton);
2507 
2508         aStr.append(CreateLink(u"JavaScript:parent.ExpandOutline()", aButton));
2509         aStr.append("</body>\r\n</html>");
2510 
2511         bOk = WriteHtml("navbar3", true, aStr.makeStringAndClear());
2512 
2513         if (mpProgress)
2514             mpProgress->SetState(++mnPagesWritten);
2515     }
2516 
2517     // ... and the outliner open
2518     if( bOk )
2519     {
2520         OUStringBuffer aStr(gaHTMLHeader);
2521         aStr.append(CreateMetaCharset());
2522         aStr.append("  <title>");
2523         aStr.append(StringToHTMLString(maPageNames[0]));
2524         aStr.append("</title>\r\n</head>\r\n");
2525         aStr.append(CreateBodyTag());
2526 
2527         aButton = SdResId(STR_HTMLEXP_NOOUTLINE);
2528         if(mnButtonThema != -1)
2529             aButton = CreateImage(GetButtonName(BTN_LESS), aButton);
2530 
2531         aStr.append(CreateLink(u"JavaScript:parent.CollapseOutline()", aButton));
2532         aStr.append("</body>\r\n</html>");
2533 
2534         bOk = WriteHtml("navbar4", true, aStr.makeStringAndClear());
2535 
2536         if (mpProgress)
2537             mpProgress->SetState(++mnPagesWritten);
2538 
2539     }
2540 
2541     return bOk;
2542 }
2543 
2544 // create button bar for standard
CreateNavBar(sal_uInt16 nSdPage,bool bIsText) const2545 OUString HtmlExport::CreateNavBar( sal_uInt16 nSdPage, bool bIsText ) const
2546 {
2547     // prepare button bar
2548     OUString aStrNavFirst(SdResId(STR_HTMLEXP_FIRSTPAGE));
2549     OUString aStrNavPrev(SdResId(STR_PUBLISH_BACK));
2550     OUString aStrNavNext(SdResId(STR_PUBLISH_NEXT));
2551     OUString aStrNavLast(SdResId(STR_HTMLEXP_LASTPAGE));
2552     OUString aStrNavContent(SdResId(STR_PUBLISH_OUTLINE));
2553     OUString aStrNavText;
2554     if( bIsText )
2555     {
2556         aStrNavText = SdResId(STR_HTMLEXP_SETGRAPHIC);
2557     }
2558     else
2559     {
2560         aStrNavText = SdResId(STR_HTMLEXP_SETTEXT);
2561     }
2562 
2563     if(!bIsText && mnButtonThema != -1)
2564     {
2565         if(nSdPage<1 || mnSdPageCount == 1)
2566         {
2567             aStrNavFirst = CreateImage(GetButtonName(BTN_FIRST_0), aStrNavFirst);
2568             aStrNavPrev  = CreateImage(GetButtonName(BTN_PREV_0), aStrNavPrev);
2569         }
2570         else
2571         {
2572             aStrNavFirst = CreateImage(GetButtonName(BTN_FIRST_1), aStrNavFirst);
2573             aStrNavPrev  = CreateImage(GetButtonName(BTN_PREV_1), aStrNavPrev);
2574         }
2575 
2576         if(nSdPage == mnSdPageCount-1 || mnSdPageCount == 1)
2577         {
2578             aStrNavNext    = CreateImage(GetButtonName(BTN_NEXT_0), aStrNavNext);
2579             aStrNavLast    = CreateImage(GetButtonName(BTN_LAST_0), aStrNavLast);
2580         }
2581         else
2582         {
2583             aStrNavNext    = CreateImage(GetButtonName(BTN_NEXT_1), aStrNavNext);
2584             aStrNavLast    = CreateImage(GetButtonName(BTN_LAST_1), aStrNavLast);
2585         }
2586 
2587         aStrNavContent = CreateImage(GetButtonName(BTN_INDEX), aStrNavContent);
2588         aStrNavText    = CreateImage(GetButtonName(BTN_TEXT), aStrNavText);
2589     }
2590 
2591     OUStringBuffer aStr("<center>\r\n"); //<table><tr>\r\n");
2592 
2593     // first page
2594     if(nSdPage > 0)
2595         aStr.append(CreateLink( bIsText ? maTextFiles[0] : maHTMLFiles[0],aStrNavFirst));
2596     else
2597         aStr.append(aStrNavFirst);
2598     aStr.append(' ');
2599 
2600     // to Previous page
2601     if(nSdPage > 0)
2602         aStr.append(CreateLink( bIsText ? maTextFiles[nSdPage-1]
2603                                         : maHTMLFiles[nSdPage-1], aStrNavPrev));
2604     else
2605         aStr.append(aStrNavPrev);
2606     aStr.append(' ');
2607 
2608     // to Next page
2609     if(nSdPage < mnSdPageCount-1)
2610         aStr.append(CreateLink( bIsText ? maTextFiles[nSdPage+1]
2611                                         : maHTMLFiles[nSdPage+1], aStrNavNext));
2612     else
2613         aStr.append(aStrNavNext);
2614     aStr.append(' ');
2615 
2616     // to Last page
2617     if(nSdPage < mnSdPageCount-1)
2618         aStr.append(CreateLink( bIsText ? maTextFiles[mnSdPageCount-1]
2619                                         : maHTMLFiles[mnSdPageCount-1],
2620                                 aStrNavLast));
2621     else
2622         aStr.append(aStrNavLast);
2623     aStr.append(' ');
2624 
2625     // to Index page
2626     if (mbContentsPage)
2627     {
2628         aStr.append(CreateLink(maIndex, aStrNavContent));
2629         aStr.append(' ');
2630     }
2631 
2632     // Text/Graphics
2633     if(mbImpress)
2634     {
2635         aStr.append(CreateLink( bIsText ? (mbFrames ? maFramePage : maHTMLFiles[nSdPage])
2636                                         : maTextFiles[nSdPage], aStrNavText));
2637 
2638     }
2639 
2640     aStr.append("</center><br>\r\n");
2641 
2642     return aStr.makeStringAndClear();
2643 }
2644 
2645 // export navigation graphics from button set
CreateBitmaps()2646 void HtmlExport::CreateBitmaps()
2647 {
2648     if(mnButtonThema == -1 || !mpButtonSet)
2649         return;
2650 
2651     for( int nButton = 0; nButton != SAL_N_ELEMENTS(pButtonNames); nButton++ )
2652     {
2653         if(!mbFrames && (nButton == BTN_MORE || nButton == BTN_LESS))
2654             continue;
2655 
2656         if(!mbImpress && (nButton == BTN_TEXT || nButton == BTN_MORE || nButton == BTN_LESS ))
2657             continue;
2658 
2659         OUString aFull = maExportPath + GetButtonName(nButton);
2660         mpButtonSet->exportButton( mnButtonThema, aFull, GetButtonName(nButton) );
2661     }
2662 }
2663 
2664 // creates the <body> tag, including the specified color attributes
CreateBodyTag() const2665 OUString HtmlExport::CreateBodyTag() const
2666 {
2667     OUStringBuffer aStr( "<body" );
2668 
2669     if( mbUserAttr || mbDocColors )
2670     {
2671         Color aTextColor( maTextColor );
2672         if( (aTextColor == COL_AUTO) && (!maBackColor.IsDark()) )
2673             aTextColor = COL_BLACK;
2674 
2675         aStr.append(" text=\"");
2676         aStr.append(ColorToHTMLString( aTextColor ));
2677         aStr.append("\" bgcolor=\"");
2678         aStr.append(ColorToHTMLString( maBackColor ));
2679         aStr.append("\" link=\"");
2680         aStr.append(ColorToHTMLString( maLinkColor ));
2681         aStr.append("\" vlink=\"");
2682         aStr.append(ColorToHTMLString( maVLinkColor ));
2683         aStr.append("\" alink=\"");
2684         aStr.append(ColorToHTMLString( maALinkColor ));
2685         aStr.append("\"");
2686     }
2687 
2688     aStr.append(">\r\n");
2689 
2690     return aStr.makeStringAndClear();
2691 }
2692 
2693 // creates a hyperlink
CreateLink(std::u16string_view aLink,std::u16string_view aText,std::u16string_view aTarget)2694 OUString HtmlExport::CreateLink( std::u16string_view aLink,
2695                                  std::u16string_view aText,
2696                                  std::u16string_view aTarget )
2697 {
2698     OUStringBuffer aStr( "<a href=\"" );
2699     aStr.append(aLink);
2700     if (!aTarget.empty())
2701     {
2702         aStr.append("\" target=\"");
2703         aStr.append(aTarget);
2704     }
2705     aStr.append("\">");
2706     aStr.append(aText);
2707     aStr.append("</a>");
2708 
2709     return aStr.makeStringAndClear();
2710 }
2711 
2712 // creates an image tag
CreateImage(std::u16string_view aImage,std::u16string_view aAltText)2713 OUString HtmlExport::CreateImage( std::u16string_view aImage, std::u16string_view aAltText )
2714 {
2715     OUStringBuffer aStr( "<img src=\"");
2716     aStr.append(aImage);
2717     aStr.append("\" border=0");
2718 
2719     if (!aAltText.empty())
2720     {
2721         aStr.append(" alt=\"");
2722         aStr.append(aAltText);
2723         aStr.append('"');
2724     }
2725     else
2726     {
2727         // Agerskov: HTML 4.01 has to have an alt attribute even if it is an empty string
2728         aStr.append(" alt=\"\"");
2729     }
2730 
2731     aStr.append('>');
2732 
2733     return aStr.makeStringAndClear();
2734 }
2735 
2736 // create area for a circle; we expect pixel coordinates
ColorToHTMLString(Color aColor)2737 OUString HtmlExport::ColorToHTMLString( Color aColor )
2738 {
2739     static const char hex[] = "0123456789ABCDEF";
2740     OUStringBuffer aStr( "#xxxxxx" );
2741     aStr[1] = hex[(aColor.GetRed() >> 4) & 0xf];
2742     aStr[2] = hex[aColor.GetRed() & 0xf];
2743     aStr[3] = hex[(aColor.GetGreen() >> 4) & 0xf];
2744     aStr[4] = hex[aColor.GetGreen() & 0xf];
2745     aStr[5] = hex[(aColor.GetBlue() >> 4) & 0xf];
2746     aStr[6] = hex[aColor.GetBlue() & 0xf];
2747 
2748     return aStr.makeStringAndClear();
2749 }
2750 
2751 // create area for a circle; we expect pixel coordinates
CreateHTMLCircleArea(sal_uLong nRadius,sal_uLong nCenterX,sal_uLong nCenterY,std::u16string_view rHRef)2752 OUString HtmlExport::CreateHTMLCircleArea( sal_uLong nRadius,
2753                                          sal_uLong nCenterX,
2754                                          sal_uLong nCenterY,
2755                                          std::u16string_view rHRef )
2756 {
2757     OUString aStr(
2758         "<area shape=\"circle\" alt=\"\" coords=\"" +
2759         OUString::number(nCenterX) + "," +
2760         OUString::number(nCenterY) + "," +
2761         OUString::number(nRadius) +
2762         "\" href=\"" + rHRef + "\">\n");
2763 
2764     return aStr;
2765 }
2766 
2767 // create area for a polygon; we expect pixel coordinates
CreateHTMLPolygonArea(const::basegfx::B2DPolyPolygon & rPolyPolygon,Size aShift,double fFactor,std::u16string_view rHRef)2768 OUString HtmlExport::CreateHTMLPolygonArea( const ::basegfx::B2DPolyPolygon& rPolyPolygon,
2769     Size aShift, double fFactor, std::u16string_view rHRef )
2770 {
2771     OUStringBuffer aStr;
2772     const sal_uInt32 nNoOfPolygons(rPolyPolygon.count());
2773 
2774     for ( sal_uInt32 nXPoly = 0; nXPoly < nNoOfPolygons; nXPoly++ )
2775     {
2776         const ::basegfx::B2DPolygon& aPolygon = rPolyPolygon.getB2DPolygon(nXPoly);
2777         const sal_uInt32 nNoOfPoints(aPolygon.count());
2778 
2779         aStr.append("<area shape=\"polygon\" alt=\"\" coords=\"");
2780 
2781         for ( sal_uInt32 nPoint = 0; nPoint < nNoOfPoints; nPoint++ )
2782         {
2783             const ::basegfx::B2DPoint aB2DPoint(aPolygon.getB2DPoint(nPoint));
2784             Point aPnt(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY()));
2785             // coordinates are relative to the physical page origin, not the
2786             // origin of ordinates
2787             aPnt.Move(aShift.Width(), aShift.Height());
2788 
2789             aPnt.setX( static_cast<tools::Long>(aPnt.X() * fFactor) );
2790             aPnt.setY( static_cast<tools::Long>(aPnt.Y() * fFactor) );
2791             aStr.append( OUString::number(aPnt.X()) + "," + OUString::number(aPnt.Y()) );
2792 
2793             if (nPoint < nNoOfPoints - 1)
2794                 aStr.append(',');
2795         }
2796         aStr.append(OUString::Concat("\" href=\"") + rHRef + "\">\n");
2797     }
2798 
2799     return aStr.makeStringAndClear();
2800 }
2801 
2802 // create area for a rectangle; we expect pixel coordinates
CreateHTMLRectArea(const::tools::Rectangle & rRect,std::u16string_view rHRef)2803 OUString HtmlExport::CreateHTMLRectArea( const ::tools::Rectangle& rRect,
2804                                        std::u16string_view rHRef )
2805 {
2806     OUString aStr(
2807         "<area shape=\"rect\" alt=\"\" coords=\"" +
2808         OUString::number(rRect.Left()) + "," +
2809         OUString::number(rRect.Top()) + "," +
2810         OUString::number(rRect.Right()) + "," +
2811         OUString::number(rRect.Bottom()) +
2812         "\" href=\"" + rHRef + "\">\n");
2813 
2814     return aStr;
2815 }
2816 
2817 // escapes a string for html
StringToHTMLString(const OUString & rString)2818 OUString HtmlExport::StringToHTMLString( const OUString& rString )
2819 {
2820     SvMemoryStream aMemStm;
2821     HTMLOutFuncs::Out_String( aMemStm, rString, RTL_TEXTENCODING_UTF8 );
2822     aMemStm.WriteChar( char(0) );
2823     sal_Int32 nLength = strlen(static_cast<char const *>(aMemStm.GetData()));
2824     return OUString( static_cast<char const *>(aMemStm.GetData()), nLength, RTL_TEXTENCODING_UTF8 );
2825 }
2826 
2827 // creates a URL for a specific page
CreatePageURL(sal_uInt16 nPgNum)2828 OUString HtmlExport::CreatePageURL( sal_uInt16 nPgNum )
2829 {
2830     if(mbFrames)
2831     {
2832         return OUString("JavaScript:parent.NavigateAbs(" +
2833                         OUString::number(nPgNum) + ")");
2834     }
2835     else
2836         return maHTMLFiles[nPgNum];
2837 }
2838 
CopyScript(std::u16string_view rPath,const OUString & rSource,const OUString & rDest,bool bUnix)2839 bool HtmlExport::CopyScript( std::u16string_view rPath, const OUString& rSource, const OUString& rDest, bool bUnix /* = false */ )
2840 {
2841     INetURLObject   aURL( SvtPathOptions().GetConfigPath() );
2842     OUStringBuffer aScriptBuf;
2843 
2844     aURL.Append( u"webcast" );
2845     aURL.Append( rSource );
2846 
2847     meEC.SetContext( STR_HTMLEXP_ERROR_OPEN_FILE, rSource );
2848 
2849     ErrCode     nErr = ERRCODE_NONE;
2850     std::unique_ptr<SvStream> pIStm = ::utl::UcbStreamHelper::CreateStream( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ );
2851 
2852     if( pIStm )
2853     {
2854         OString aLine;
2855 
2856         while( pIStm->ReadLine( aLine ) )
2857         {
2858             aScriptBuf.appendAscii( aLine.getStr() );
2859             if( bUnix )
2860             {
2861                 aScriptBuf.append("\n");
2862             }
2863             else
2864             {
2865                 aScriptBuf.append("\r\n");
2866             }
2867         }
2868 
2869         nErr = pIStm->GetError();
2870         pIStm.reset();
2871     }
2872 
2873     if( nErr != ERRCODE_NONE )
2874     {
2875         ErrorHandler::HandleError( nErr );
2876         return static_cast<bool>(nErr);
2877     }
2878 
2879     OUString aScript(aScriptBuf.makeStringAndClear());
2880     aScript = aScript.replaceAll("$$1", getDocumentTitle());
2881     aScript = aScript.replaceAll("$$2", RESTOHTML(STR_WEBVIEW_SAVE));
2882     aScript = aScript.replaceAll("$$3", maCGIPath);
2883     aScript = aScript.replaceAll("$$4", OUString::number(mnWidthPixel));
2884     aScript = aScript.replaceAll("$$5", OUString::number(mnHeightPixel));
2885 
2886     OUString aDest(rPath + rDest);
2887 
2888     meEC.SetContext( STR_HTMLEXP_ERROR_CREATE_FILE, rDest );
2889     // write script file
2890     {
2891         EasyFile aFile;
2892         SvStream* pStr;
2893         nErr = aFile.createStream(aDest, pStr);
2894         if(nErr == ERRCODE_NONE)
2895         {
2896             OString aStr(OUStringToOString(aScript, RTL_TEXTENCODING_UTF8));
2897             pStr->WriteOString( aStr );
2898             aFile.close();
2899         }
2900     }
2901 
2902     if (mpProgress)
2903         mpProgress->SetState(++mnPagesWritten);
2904 
2905     if( nErr != ERRCODE_NONE )
2906         ErrorHandler::HandleError( nErr );
2907 
2908     return nErr == ERRCODE_NONE;
2909 }
2910 
2911 static const char * ASP_Scripts[] = { "common.inc", "webcast.asp", "show.asp", "savepic.asp", "poll.asp", "editpic.asp" };
2912 
2913 /** creates and saves the ASP scripts for WebShow */
CreateASPScripts()2914 bool HtmlExport::CreateASPScripts()
2915 {
2916     for(const char * p : ASP_Scripts)
2917     {
2918         OUString aScript = OUString::createFromAscii(p);
2919 
2920         if(!CopyScript(maExportPath, aScript, aScript))
2921             return false;
2922     }
2923 
2924     return CopyScript(maExportPath, "edit.asp", maIndex);
2925 }
2926 
2927 static const char *PERL_Scripts[] = { "webcast.pl", "common.pl", "editpic.pl", "poll.pl", "savepic.pl", "show.pl" };
2928 
2929 // creates and saves the PERL scripts for WebShow
CreatePERLScripts()2930 bool HtmlExport::CreatePERLScripts()
2931 {
2932     for(const char * p : PERL_Scripts)
2933     {
2934         OUString aScript = OUString::createFromAscii(p);
2935 
2936         if(!CopyScript(maExportPath, aScript, aScript, true))
2937             return false;
2938     }
2939 
2940     if (!CopyScript(maExportPath, "edit.pl", maIndex, true))
2941         return false;
2942 
2943     if (!CopyScript(maExportPath, "index.pl", maIndexUrl, true))
2944         return false;
2945 
2946     return true;
2947 }
2948 
2949 // creates a list with names of the saved images
CreateImageFileList()2950 bool HtmlExport::CreateImageFileList()
2951 {
2952     OUStringBuffer aStr;
2953     for( sal_uInt16 nSdPage = 0; nSdPage < mnSdPageCount; nSdPage++)
2954     {
2955         aStr.append(static_cast<sal_Int32>(nSdPage + 1));
2956         aStr.append(';');
2957         aStr.append(maURLPath);
2958         aStr.append(maImageFiles[nSdPage]);
2959         aStr.append("\r\n");
2960     }
2961 
2962     bool bOk = WriteHtml("picture.txt", false, aStr.makeStringAndClear());
2963 
2964     if (mpProgress)
2965         mpProgress->SetState(++mnPagesWritten);
2966 
2967     return bOk;
2968 }
2969 
2970 // creates a file with the actual page number
CreateImageNumberFile()2971 bool HtmlExport::CreateImageNumberFile()
2972 {
2973     OUString aFileName("currpic.txt");
2974     OUString aFull(maExportPath + aFileName);
2975 
2976     meEC.SetContext( STR_HTMLEXP_ERROR_CREATE_FILE, aFileName );
2977     EasyFile aFile;
2978     SvStream* pStr;
2979     ErrCode nErr = aFile.createStream(aFull, pStr);
2980     if(nErr == ERRCODE_NONE)
2981     {
2982         pStr->WriteCharPtr( "1" );
2983         aFile.close();
2984     }
2985 
2986     if (mpProgress)
2987         mpProgress->SetState(++mnPagesWritten);
2988 
2989     if( nErr != ERRCODE_NONE )
2990         ErrorHandler::HandleError( nErr );
2991 
2992     return nErr == ERRCODE_NONE;
2993 }
2994 
InsertSound(const OUString & rSoundFile)2995 OUString HtmlExport::InsertSound( const OUString& rSoundFile )
2996 {
2997     if (rSoundFile.isEmpty())
2998         return rSoundFile;
2999 
3000     INetURLObject   aURL( rSoundFile );
3001     OUString aSoundFileName = aURL.getName();
3002 
3003     DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
3004 
3005     OUString aStr("<embed src=\"" + aSoundFileName +
3006         "\" hidden=\"true\" autostart=\"true\">");
3007 
3008     CopyFile(rSoundFile, maExportPath + aSoundFileName);
3009 
3010     return aStr;
3011 }
3012 
CopyFile(const OUString & rSourceFile,const OUString & rDestFile)3013 bool HtmlExport::CopyFile( const OUString& rSourceFile, const OUString& rDestFile )
3014 {
3015     meEC.SetContext( STR_HTMLEXP_ERROR_COPY_FILE, rSourceFile, rDestFile );
3016     osl::FileBase::RC Error = osl::File::copy( rSourceFile, rDestFile );
3017 
3018     if( Error != osl::FileBase::E_None )
3019     {
3020         ErrorHandler::HandleError(ErrCode(Error));
3021         return false;
3022     }
3023     else
3024     {
3025         return true;
3026     }
3027 }
3028 
checkFileExists(Reference<css::ucb::XSimpleFileAccess3> const & xFileAccess,std::u16string_view aFileName)3029 bool HtmlExport::checkFileExists( Reference< css::ucb::XSimpleFileAccess3 > const & xFileAccess, std::u16string_view aFileName )
3030 {
3031     try
3032     {
3033         OUString url = maExportPath + aFileName;
3034         return xFileAccess->exists( url );
3035     }
3036     catch( css::uno::Exception& )
3037     {
3038         TOOLS_WARN_EXCEPTION( "sd", "sd::HtmlExport::checkFileExists()" );
3039     }
3040 
3041     return false;
3042 }
3043 
checkForExistingFiles()3044 bool HtmlExport::checkForExistingFiles()
3045 {
3046     bool bFound = false;
3047 
3048     try
3049     {
3050         Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
3051         uno::Reference<ucb::XSimpleFileAccess3> xFA(ucb::SimpleFileAccess::create(xContext));
3052 
3053         sal_uInt16 nSdPage;
3054         for( nSdPage = 0; !bFound && (nSdPage < mnSdPageCount); nSdPage++)
3055         {
3056             if( checkFileExists( xFA, maImageFiles[nSdPage] ) ||
3057                 checkFileExists( xFA, maHTMLFiles[nSdPage] ) ||
3058                 checkFileExists( xFA, maThumbnailFiles[nSdPage] ) ||
3059                 checkFileExists( xFA, maPageNames[nSdPage] ) ||
3060                 checkFileExists( xFA, maTextFiles[nSdPage] ) )
3061             {
3062                 bFound = true;
3063             }
3064         }
3065 
3066         if( !bFound && mbDownload )
3067             bFound = checkFileExists( xFA, maDocFileName );
3068 
3069         if( !bFound && mbFrames )
3070             bFound = checkFileExists( xFA, maFramePage );
3071 
3072         if( bFound )
3073         {
3074             OUString aSystemPath;
3075             osl::FileBase::getSystemPathFromFileURL( maExportPath, aSystemPath );
3076             OUString aMsg(SdResId(STR_OVERWRITE_WARNING));
3077             aMsg = aMsg.replaceFirst( "%FILENAME", aSystemPath );
3078 
3079             std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(nullptr,
3080                                                        VclMessageType::Warning, VclButtonsType::YesNo,
3081                                                        aMsg));
3082             xWarn->set_default_response(RET_YES);
3083             bFound = (RET_NO == xWarn->run());
3084         }
3085     }
3086     catch( Exception& )
3087     {
3088         TOOLS_WARN_EXCEPTION( "sd", "sd::HtmlExport::checkForExistingFiles()" );
3089         bFound = false;
3090     }
3091 
3092     return bFound;
3093 }
3094 
GetButtonName(int nButton)3095 OUString HtmlExport::GetButtonName( int nButton )
3096 {
3097     return OUString::createFromAscii(pButtonNames[nButton]);
3098 }
3099 
EasyFile()3100 EasyFile::EasyFile() : bOpen(false)
3101 {
3102 }
3103 
~EasyFile()3104 EasyFile::~EasyFile()
3105 {
3106     if( bOpen )
3107         close();
3108 }
3109 
createStream(const OUString & rUrl,SvStream * & rpStr)3110 ErrCode EasyFile::createStream(  const OUString& rUrl, SvStream* &rpStr )
3111 {
3112     if(bOpen)
3113         close();
3114 
3115     OUString aFileName;
3116     createFileName( rUrl, aFileName );
3117 
3118     ErrCode nErr = ERRCODE_NONE;
3119     pOStm = ::utl::UcbStreamHelper::CreateStream( aFileName, StreamMode::WRITE | StreamMode::TRUNC );
3120     if( pOStm )
3121     {
3122         bOpen = true;
3123         nErr = pOStm->GetError();
3124     }
3125     else
3126     {
3127         nErr = ERRCODE_SFX_CANTCREATECONTENT;
3128     }
3129 
3130     if( nErr != ERRCODE_NONE )
3131     {
3132         bOpen = false;
3133         pOStm.reset();
3134     }
3135 
3136     rpStr = pOStm.get();
3137 
3138     return nErr;
3139 }
3140 
createFileName(const OUString & rURL,OUString & rFileName)3141 void EasyFile::createFileName(  const OUString& rURL, OUString& rFileName )
3142 {
3143     if( bOpen )
3144         close();
3145 
3146     INetURLObject aURL( rURL );
3147 
3148     if( aURL.GetProtocol() == INetProtocol::NotValid )
3149     {
3150         OUString aURLStr;
3151         osl::FileBase::getFileURLFromSystemPath( rURL, aURLStr );
3152         aURL = INetURLObject( aURLStr );
3153     }
3154     DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "invalid URL" );
3155     rFileName = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
3156 }
3157 
close()3158 void EasyFile::close()
3159 {
3160     pOStm.reset();
3161     bOpen = false;
3162 }
3163 
3164 // This class helps reporting errors during file i/o
HtmlErrorContext()3165 HtmlErrorContext::HtmlErrorContext()
3166     : ErrorContext(nullptr)
3167     , mpResId(nullptr)
3168 {
3169 }
3170 
GetString(ErrCode,OUString & rCtxStr)3171 bool HtmlErrorContext::GetString( ErrCode, OUString& rCtxStr )
3172 {
3173     DBG_ASSERT(mpResId, "No error context set");
3174     if (!mpResId)
3175         return false;
3176 
3177     rCtxStr = SdResId(mpResId);
3178 
3179     rCtxStr = rCtxStr.replaceAll( "$(URL1)", maURL1 );
3180     rCtxStr = rCtxStr.replaceAll( "$(URL2)", maURL2 );
3181 
3182     return true;
3183 }
3184 
SetContext(const char * pResId,const OUString & rURL)3185 void HtmlErrorContext::SetContext(const char* pResId, const OUString& rURL)
3186 {
3187     mpResId = pResId;
3188     maURL1 = rURL;
3189     maURL2.clear();
3190 }
3191 
SetContext(const char * pResId,const OUString & rURL1,const OUString & rURL2)3192 void HtmlErrorContext::SetContext(const char* pResId, const OUString& rURL1, const OUString& rURL2 )
3193 {
3194     mpResId = pResId;
3195     maURL1 = rURL1;
3196     maURL2 = rURL2;
3197 }
3198 
3199 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3200