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 <svx/svditer.hxx>
21 #include <svx/svdograf.hxx>
22 #include <svx/svdoole2.hxx>
23 #include <svx/svdpage.hxx>
24 #include <svx/xoutbmp.hxx>
25 #include <svx/svdxcgv.hxx>
26 #include <svtools/htmlkywd.hxx>
27 #include <svtools/htmlout.hxx>
28 #include <svl/urihelper.hxx>
29 #include <tools/stream.hxx>
30 #include <tools/urlobj.hxx>
31 
32 #include <htmlexp.hxx>
33 #include <global.hxx>
34 #include <document.hxx>
35 #include <drwlayer.hxx>
36 #include <rtl/strbuf.hxx>
37 
38 using namespace com::sun::star;
39 
PrepareGraphics(ScDrawLayer * pDrawLayer,SCTAB nTab,SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow)40 void ScHTMLExport::PrepareGraphics( ScDrawLayer* pDrawLayer, SCTAB nTab,
41         SCCOL nStartCol, SCROW nStartRow,   SCCOL nEndCol, SCROW nEndRow )
42 {
43     if ( !pDrawLayer->HasObjectsInRows( nTab, nStartRow, nEndRow ) )
44         return;
45 
46     SdrPage* pDrawPage = pDrawLayer->GetPage( static_cast<sal_uInt16>(nTab) );
47     if ( !pDrawPage )
48         return;
49 
50     bTabHasGraphics = true;
51     FillGraphList( pDrawPage, nTab, nStartCol, nStartRow, nEndCol, nEndRow );
52     size_t ListSize = aGraphList.size();
53     for ( size_t i = 0; i < ListSize; ++i )
54     {
55         ScHTMLGraphEntry* pE = &aGraphList[ i ];
56         if ( !pE->bInCell )
57         {   // not all cells: table next to some
58             bTabAlignedLeft = true;
59             break;
60         }
61     }
62 }
63 
FillGraphList(const SdrPage * pPage,SCTAB nTab,SCCOL nStartCol,SCROW nStartRow,SCCOL nEndCol,SCROW nEndRow)64 void ScHTMLExport::FillGraphList( const SdrPage* pPage, SCTAB nTab,
65         SCCOL nStartCol, SCROW nStartRow,   SCCOL nEndCol, SCROW nEndRow )
66 {
67     if ( !pPage->GetObjCount() )
68         return;
69 
70     tools::Rectangle aRect;
71     if ( !bAll )
72         aRect = pDoc->GetMMRect( nStartCol, nStartRow, nEndCol, nEndRow, nTab );
73     SdrObjListIter aIter( pPage, SdrIterMode::Flat );
74     SdrObject* pObject = aIter.Next();
75     while ( pObject )
76     {
77         tools::Rectangle aObjRect = pObject->GetCurrentBoundRect();
78         if ( (bAll || aRect.IsInside( aObjRect )) && !ScDrawLayer::IsNoteCaption(pObject) )
79         {
80             Size aSpace;
81             ScRange aR = pDoc->GetRange( nTab, aObjRect );
82             // Rectangle in mm/100
83             Size aSize( MMToPixel( aObjRect.GetSize() ) );
84             // If the image is somewhere in a merged range we must
85             // move the anchor to the upper left (THE span cell).
86             pDoc->ExtendOverlapped( aR );
87             SCCOL nCol1 = aR.aStart.Col();
88             SCROW nRow1 = aR.aStart.Row();
89             SCCOL nCol2 = aR.aEnd.Col();
90             SCROW nRow2 = aR.aEnd.Row();
91             // All cells empty under object?
92             bool bInCell = (pDoc->GetEmptyLinesInBlock(
93                 nCol1, nRow1, nTab, nCol2, nRow2, nTab, DIR_TOP )
94                 == static_cast< SCSIZE >( nRow2 - nRow1 ));    // rows-1 !
95             if ( bInCell )
96             {   // Spacing in spanning cell
97                 tools::Rectangle aCellRect = pDoc->GetMMRect(
98                     nCol1, nRow1, nCol2, nRow2, nTab );
99                 aSpace = MMToPixel( Size(
100                     aCellRect.GetWidth() - aObjRect.GetWidth(),
101                     aCellRect.GetHeight() - aObjRect.GetHeight() ));
102                 aSpace.AdjustWidth((nCol2-nCol1) * (nCellSpacing+1) );
103                 aSpace.AdjustHeight((nRow2-nRow1) * (nCellSpacing+1) );
104                 aSpace.setWidth( aSpace.Width() / 2 );
105                 aSpace.setHeight( aSpace.Height() / 2 );
106             }
107             aGraphList.emplace_back( pObject,
108                 aR, aSize, bInCell, aSpace );
109         }
110         pObject = aIter.Next();
111     }
112 }
113 
WriteGraphEntry(ScHTMLGraphEntry * pE)114 void ScHTMLExport::WriteGraphEntry( ScHTMLGraphEntry* pE )
115 {
116     SdrObject* pObject = pE->pObject;
117     OStringBuffer aBuf;
118     aBuf.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_width).append('=').
119         append(static_cast<sal_Int32>(pE->aSize.Width()));
120     aBuf.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_height).append('=').
121         append(static_cast<sal_Int32>(pE->aSize.Height()));
122     if ( pE->bInCell )
123     {
124         aBuf.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_hspace).append('=').
125             append(static_cast<sal_Int32>(pE->aSpace.Width()));
126         aBuf.append(' ').append(OOO_STRING_SVTOOLS_HTML_O_vspace).append('=').
127             append(static_cast<sal_Int32>(pE->aSpace.Height()));
128     }
129     OString aOpt = aBuf.makeStringAndClear();
130     switch ( pObject->GetObjIdentifier() )
131     {
132         case OBJ_GRAF:
133         {
134             const SdrGrafObj* pSGO = static_cast<SdrGrafObj*>(pObject);
135             std::unique_ptr<SdrGrafObjGeoData> pGeo(static_cast<SdrGrafObjGeoData*>(pSGO->GetGeoData().release()));
136             sal_uInt16 nMirrorCase = (pGeo->aGeo.nRotationAngle == 18000_deg100 ?
137                     ( pGeo->bMirrored ? 3 : 4 ) : ( pGeo->bMirrored ? 2 : 1 ));
138             bool bHMirr = ( ( nMirrorCase == 2 ) || ( nMirrorCase == 4 ) );
139             bool bVMirr = ( ( nMirrorCase == 3 ) || ( nMirrorCase == 4 ) );
140             XOutFlags nXOutFlags = XOutFlags::NONE;
141             if ( bHMirr )
142                 nXOutFlags |= XOutFlags::MirrorHorz;
143             if ( bVMirr )
144                 nXOutFlags |= XOutFlags::MirrorVert;
145             OUString aLinkName;
146             if ( pSGO->IsLinkedGraphic() )
147                 aLinkName = pSGO->GetFileName();
148             WriteImage( aLinkName, pSGO->GetGraphic(), aOpt, nXOutFlags );
149             pE->bWritten = true;
150         }
151         break;
152         case OBJ_OLE2:
153         {
154             const Graphic* pGraphic = static_cast<SdrOle2Obj*>(pObject)->GetGraphic();
155             if ( pGraphic )
156             {
157                 OUString aLinkName;
158                 WriteImage( aLinkName, *pGraphic, aOpt );
159                 pE->bWritten = true;
160             }
161         }
162         break;
163         default:
164         {
165             Graphic aGraph(SdrExchangeView::GetObjGraphic(*pObject));
166             OUString aLinkName;
167             WriteImage( aLinkName, aGraph, aOpt );
168             pE->bWritten = true;
169         }
170     }
171 }
172 
WriteImage(OUString & rLinkName,const Graphic & rGrf,std::string_view rImgOptions,XOutFlags nXOutFlags)173 void ScHTMLExport::WriteImage( OUString& rLinkName, const Graphic& rGrf,
174             std::string_view rImgOptions, XOutFlags nXOutFlags )
175 {
176     // Embedded graphic -> create an image file
177     if( rLinkName.isEmpty() )
178     {
179         if( !aStreamPath.isEmpty() )
180         {
181             // Save as a PNG
182             OUString aGrfNm( aStreamPath );
183             nXOutFlags |= XOutFlags::UseNativeIfPossible;
184             ErrCode nErr = XOutBitmap::WriteGraphic( rGrf, aGrfNm,
185                 "PNG", nXOutFlags );
186 
187             // If it worked, create a URL for the IMG tag
188             if( !nErr )
189             {
190                 rLinkName = URIHelper::SmartRel2Abs(
191                         INetURLObject(aBaseURL),
192                         aGrfNm,
193                         URIHelper::GetMaybeFileHdl());
194             }
195         }
196     }
197     else
198     {
199         // Linked graphic - figure out the URL for the IMG tag
200         if( bCopyLocalFileToINet )
201         {
202             CopyLocalFileToINet( rLinkName, aStreamPath );
203         }
204         else
205             rLinkName = URIHelper::SmartRel2Abs(
206                     INetURLObject(aBaseURL),
207                     rLinkName,
208                     URIHelper::GetMaybeFileHdl());
209     }
210 
211     // If a URL was set, output the IMG tag.
212     // <IMG SRC="..."[ rImgOptions]>
213     if( !rLinkName.isEmpty() )
214     {
215         rStrm.WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_image ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_src ).WriteCharPtr( "=\"" );
216         HTMLOutFuncs::Out_String( rStrm, URIHelper::simpleNormalizedMakeRelative(
217                     aBaseURL,
218                     rLinkName ), eDestEnc ).WriteChar( '\"' );
219         if ( !rImgOptions.empty() )
220             rStrm.WriteOString( rImgOptions );
221         rStrm.WriteChar( '>' ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() );
222     }
223 }
224 
225 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
226