1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
23 #include <sal/log.hxx>
24 #include <comphelper/lok.hxx>
25 #include <comphelper/servicedecl.hxx>
26 #include <uno/environment.h>
27 #include <com/sun/star/text/XTextDocument.hpp>
28 #include <com/sun/star/drawing/XDrawPage.hpp>
29 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
30 #include <com/sun/star/drawing/XDrawView.hpp>
31 #include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
32 #include <com/sun/star/drawing/XMasterPageTarget.hpp>
33 #include <com/sun/star/frame/Desktop.hpp>
34 #include <com/sun/star/frame/XController.hpp>
35 #include <com/sun/star/io/IOException.hpp>
36 #include <com/sun/star/view/XSelectionSupplier.hpp>
37 #include <com/sun/star/drawing/XDrawSubController.hpp>
38 #include <com/sun/star/container/XNamed.hpp>
39 #include <com/sun/star/uno/XComponentContext.hpp>
40 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
41 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
42 #include <com/sun/star/drawing/framework/XConfiguration.hpp>
43 #include <com/sun/star/drawing/framework/AnchorBindingMode.hpp>
44 #include <com/sun/star/drawing/framework/XResourceId.hpp>
45 #include <com/sun/star/drawing/framework/XResource.hpp>
46 #include <com/sun/star/drawing/framework/XView.hpp>
47 #include <com/sun/star/drawing/framework/ResourceId.hpp>
49 #include <unotools/mediadescriptor.hxx>
50 #include <unotools/ucbstreamhelper.hxx>
51 #include <unotools/streamwrap.hxx>
52 #include <tools/debug.hxx>
53 #include <tools/diagnose_ex.h>
54 #include <tools/zcodec.hxx>
56 #include <drawinglayer/primitive2d/baseprimitive2d.hxx>
57 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
59 #include "svgfilter.hxx"
60 #include "svgwriter.hxx"
62 #include <svx/unopage.hxx>
63 #include <vcl/graphicfilter.hxx>
64 #include <svx/svdpage.hxx>
65 #include <svx/svdograf.hxx>
66 #include <svl/itempool.hxx>
70 using namespace ::com::sun::star
;
74 static const char constFilterNameDraw
[] = "svg_Scalable_Vector_Graphics_Draw";
75 static const char constFilterName
[] = "svg_Scalable_Vector_Graphics";
78 SVGFilter::SVGFilter( const Reference
< XComponentContext
>& rxCtx
) :
81 mpSVGExport( nullptr ),
82 mpSVGFontExport( nullptr ),
83 mpSVGWriter( nullptr ),
84 mbSinglePage( false ),
90 mbExportShapeSelection(false),
93 mbWriterFilter(false),
95 mbImpressFilter(false),
96 mpDefaultSdrPage( nullptr ),
97 mbPresentation( false ),
102 SVGFilter::~SVGFilter()
104 DBG_ASSERT( mpSVGDoc
== nullptr, "mpSVGDoc not destroyed" );
105 DBG_ASSERT( mpSVGExport
== nullptr, "mpSVGExport not destroyed" );
106 DBG_ASSERT( mpSVGFontExport
== nullptr, "mpSVGFontExport not destroyed" );
107 DBG_ASSERT( mpSVGWriter
== nullptr, "mpSVGWriter not destroyed" );
108 DBG_ASSERT( mpObjects
== nullptr, "mpObjects not destroyed" );
111 sal_Bool SAL_CALL
SVGFilter::filter( const Sequence
< PropertyValue
>& rDescriptor
)
113 mbWriterFilter
= false;
114 mbCalcFilter
= false;
115 mbImpressFilter
= false;
117 if(mxDstDoc
.is()) // Import works for Impress / draw only
118 return filterImpressOrDraw(rDescriptor
);
122 for (sal_Int32 nInd
= 0; nInd
< rDescriptor
.getLength(); nInd
++)
124 if (rDescriptor
[nInd
].Name
== "FilterName")
126 OUString sFilterName
;
127 rDescriptor
[nInd
].Value
>>= sFilterName
;
128 if(sFilterName
== "impress_svg_Export")
130 mbImpressFilter
= true;
131 return filterImpressOrDraw(rDescriptor
);
133 else if(sFilterName
== "writer_svg_Export")
135 mbWriterFilter
= true;
136 return filterWriterOrCalc(rDescriptor
);
138 else if(sFilterName
== "calc_svg_Export")
141 return filterWriterOrCalc(rDescriptor
);
146 return filterImpressOrDraw(rDescriptor
);
151 bool SVGFilter::filterImpressOrDraw( const Sequence
< PropertyValue
>& rDescriptor
)
153 SolarMutexGuard aGuard
;
154 vcl::Window
* pFocusWindow(Application::GetFocusWindow());
159 pFocusWindow
->EnterWait();
164 // Import. Use an endless loop to have easy exits for error handling
167 // use MediaDescriptor to get needed data out of Sequence< PropertyValue >
168 utl::MediaDescriptor
aMediaDescriptor(rDescriptor
);
169 uno::Reference
<io::XInputStream
> xInputStream
;
171 xInputStream
.set(aMediaDescriptor
[utl::MediaDescriptor::PROP_INPUTSTREAM()], UNO_QUERY
);
173 if(!xInputStream
.is())
175 // we need the InputStream
179 // get the DrawPagesSupplier
180 uno::Reference
< drawing::XDrawPagesSupplier
> xDrawPagesSupplier( mxDstDoc
, uno::UNO_QUERY
);
182 if(!xDrawPagesSupplier
.is())
184 // we need the DrawPagesSupplier
189 uno::Reference
< drawing::XDrawPages
> xDrawPages
= xDrawPagesSupplier
->getDrawPages();
193 // we need the DrawPages
197 // check DrawPageCount (there should be one by default)
198 sal_Int32
nDrawPageCount(xDrawPages
->getCount());
200 if(0 == nDrawPageCount
)
202 // at least one DrawPage should be there - we need that
207 uno::Reference
< drawing::XDrawPage
> xDrawPage( xDrawPages
->getByIndex(0), uno::UNO_QUERY
);
211 // we need that DrawPage
215 // get that DrawPage's UNO API implementation
216 SvxDrawPage
* pSvxDrawPage(comphelper::getUnoTunnelImplementation
<SvxDrawPage
>(xDrawPage
));
218 if(nullptr == pSvxDrawPage
|| nullptr == pSvxDrawPage
->GetSdrPage())
220 // we need a SvxDrawPage
224 // get the SvStream to work with
225 std::unique_ptr
< SvStream
> aStream(utl::UcbStreamHelper::CreateStream(xInputStream
, true));
229 // we need the SvStream
233 // create a GraphicFilter and load the SVG (format already known, thus *could*
234 // be handed over to ImportGraphic - but detection is fast).
235 // As a bonus, zipped data is already detected and handled there
236 GraphicFilter aGraphicFilter
;
238 const ErrCode
nGraphicFilterErrorCode(
239 aGraphicFilter
.ImportGraphic(aGraphic
, OUString(), *aStream
));
241 if(ERRCODE_NONE
!= nGraphicFilterErrorCode
)
243 // SVG import error, cannot continue
247 // get the GraphicPrefSize early to check if we have any content
248 // (the SVG may contain nothing and/or just <g visibility="hidden"> stuff...)
249 const Size
aGraphicPrefSize(aGraphic
.GetPrefSize());
251 if(0 == aGraphicPrefSize
.Width() || 0 == aGraphicPrefSize
.Height())
253 // SVG has no displayable content, stop import.
254 // Also possible would be to get the sequence< Primitives >
255 // from aGraphic and check if it is empty.
256 // Possibility to set some error message here to tell
257 // the user what/why loading went wrong, but I do not
258 // know how this could be done here
262 // tdf#118232 Get the sequence of primitives and check if geometry is completely
263 // hidden. If so, there is no need to add a SdrObject at all
264 const VectorGraphicDataPtr
& rVectorGraphicData(aGraphic
.getVectorGraphicData());
265 bool bContainsNoGeometry(false);
267 if(bool(rVectorGraphicData
) && VectorGraphicDataType::Svg
== rVectorGraphicData
->getVectorGraphicDataType())
269 const drawinglayer::primitive2d::Primitive2DContainer
aContainer(rVectorGraphicData
->getPrimitive2DSequence());
271 if(!aContainer
.empty())
273 bool bAllAreHiddenGeometry(true);
275 for(const auto& rCandidate
: aContainer
)
279 // try to cast to BasePrimitive2D implementation
280 const drawinglayer::primitive2d::BasePrimitive2D
* pBasePrimitive(
281 dynamic_cast< const drawinglayer::primitive2d::BasePrimitive2D
* >(rCandidate
.get()));
283 if(pBasePrimitive
&& PRIMITIVE2D_ID_HIDDENGEOMETRYPRIMITIVE2D
!= pBasePrimitive
->getPrimitive2DID())
285 bAllAreHiddenGeometry
= false;
291 if(bAllAreHiddenGeometry
)
293 bContainsNoGeometry
= true;
298 // create a SdrModel-GraphicObject to insert to page
299 SdrPage
* pTargetSdrPage(pSvxDrawPage
->GetSdrPage());
300 std::unique_ptr
< SdrGrafObj
, SdrObjectFreeOp
> aNewSdrGrafObj
;
302 // tdf#118232 only add an SdrGrafObj when we have Geometry
303 if(!bContainsNoGeometry
)
305 aNewSdrGrafObj
.reset(
307 pTargetSdrPage
->getSdrModelFromSdrPage(),
311 // Evtl. adapt the GraphicPrefSize to target-MapMode of target-Model
312 // (should be 100thmm here, but just stay safe by doing the conversion)
313 const MapMode
aGraphicPrefMapMode(aGraphic
.GetPrefMapMode());
314 const MapUnit
eDestUnit(pTargetSdrPage
->getSdrModelFromSdrPage().GetItemPool().GetMetric(0));
315 const MapUnit
eSrcUnit(aGraphicPrefMapMode
.GetMapUnit());
316 Size
aGraphicSize(aGraphicPrefSize
);
318 if (eDestUnit
!= eSrcUnit
)
321 OutputDevice::LogicToLogic(aGraphicSize
.Width(), eSrcUnit
, eDestUnit
),
322 OutputDevice::LogicToLogic(aGraphicSize
.Height(), eSrcUnit
, eDestUnit
));
325 // Based on GraphicSize, set size of Page. Do not forget to adapt PageBorders,
326 // but interpret them relative to PageSize so that they do not 'explode/shrink'
327 // in comparison. Use a common scaling factor for hor/ver to not get
328 // asynchronous border distances, though. All in all this will adapt borders
329 // nicely and is based on office-defaults for standard-page-border-sizes.
330 const Size
aPageSize(pTargetSdrPage
->GetSize());
331 const double fBorderRelation((
332 static_cast< double >(pTargetSdrPage
->GetLeftBorder()) / aPageSize
.Width() +
333 static_cast< double >(pTargetSdrPage
->GetRightBorder()) / aPageSize
.Width() +
334 static_cast< double >(pTargetSdrPage
->GetUpperBorder()) / aPageSize
.Height() +
335 static_cast< double >(pTargetSdrPage
->GetLowerBorder()) / aPageSize
.Height()) / 4.0);
336 const long nAllBorder(basegfx::fround((aGraphicSize
.Width() + aGraphicSize
.Height()) * fBorderRelation
* 0.5));
338 // Adapt PageSize and Border stuff. To get all MasterPages and PresObjs
339 // correctly adapted, do not just use
340 // pTargetSdrPage->SetBorder(...) and
341 // pTargetSdrPage->SetSize(...),
342 // but ::adaptSizeAndBorderForAllPages
343 // Do use original Size and borders to get as close to original
344 // as possible for better turn-arounds.
345 pTargetSdrPage
->getSdrModelFromSdrPage().adaptSizeAndBorderForAllPages(
347 aGraphicSize
.Width(),
348 aGraphicSize
.Height()),
354 // tdf#118232 set pos/size at SdrGraphicObj - use zero position for
355 // better turn-around results
356 if(!bContainsNoGeometry
)
358 aNewSdrGrafObj
->SetSnapRect(
363 // insert to page (owner change of SdrGrafObj)
364 pTargetSdrPage
->InsertObject(aNewSdrGrafObj
.release());
367 // done - set positive result now
370 // always leave helper endless loop
374 else if( mxSrcDoc
.is() )
376 // #i124608# detect selection
377 bool bSelectionOnly
= false;
378 bool bGotSelection
= false;
380 // when using LibreOfficeKit, default to exporting everything (-1)
381 bool bPageProvided
= comphelper::LibreOfficeKit::isActive();
382 sal_Int32 nPageToExport
= -1;
384 for (sal_Int32 nInd
= 0; nInd
< rDescriptor
.getLength(); nInd
++)
386 if (rDescriptor
[nInd
].Name
== "SelectionOnly")
388 // #i124608# extract single selection wanted from dialog return values
389 rDescriptor
[nInd
].Value
>>= bSelectionOnly
;
390 bPageProvided
= false;
392 else if (rDescriptor
[nInd
].Name
== "PagePos")
394 rDescriptor
[nInd
].Value
>>= nPageToExport
;
395 bPageProvided
= true;
399 uno::Reference
<frame::XDesktop2
> xDesktop(frame::Desktop::create(mxContext
));
400 uno::Reference
<frame::XController
> xController
;
401 if (xDesktop
->getCurrentFrame().is() && !bPageProvided
) // Manage headless case
403 uno::Reference
<frame::XFrame
> xFrame(xDesktop
->getCurrentFrame(), uno::UNO_SET_THROW
);
404 xController
.set(xFrame
->getController(), uno::UNO_SET_THROW
);
405 uno::Reference
<drawing::XDrawView
> xDrawView(xController
, uno::UNO_QUERY_THROW
);
406 uno::Reference
<drawing::framework::XControllerManager
> xManager(xController
, uno::UNO_QUERY_THROW
);
407 uno::Reference
<drawing::framework::XConfigurationController
> xConfigController(xManager
->getConfigurationController());
409 // which view configuration are we in?
411 // * traverse Impress resources to find slide preview pane, grab selection from there
412 // * otherwise, fallback to current slide
414 uno::Sequence
<uno::Reference
<drawing::framework::XResourceId
> > aResIds(
415 xConfigController
->getCurrentConfiguration()->getResources(
416 uno::Reference
<drawing::framework::XResourceId
>(),
418 drawing::framework::AnchorBindingMode_INDIRECT
));
420 for( sal_Int32 i
=0; i
<aResIds
.getLength(); ++i
)
422 // can we somehow obtain the slidesorter from the Impress framework?
423 if( aResIds
[i
]->getResourceURL() == "private:resource/view/SlideSorter" )
425 // got it, grab current selection from there
426 uno::Reference
<drawing::framework::XResource
> xRes(
427 xConfigController
->getResource(aResIds
[i
]));
429 uno::Reference
< view::XSelectionSupplier
> xSelectionSupplier(
432 if( xSelectionSupplier
.is() )
434 uno::Any aSelection
= xSelectionSupplier
->getSelection();
435 if( aSelection
.hasValue() )
437 Sequence
< Reference
< XInterface
> > aSelectedPageSequence
;
438 aSelection
>>= aSelectedPageSequence
;
439 mSelectedPages
.resize( aSelectedPageSequence
.getLength() );
440 for( size_t j
=0; j
<mSelectedPages
.size(); ++j
)
442 uno::Reference
< drawing::XDrawPage
> xDrawPage( aSelectedPageSequence
[j
],
444 mSelectedPages
[j
] = xDrawPage
;
447 // and stop looping. It is likely not getting better
454 if( mSelectedPages
.empty() )
456 // apparently failed to clean selection - fallback to current page
457 mSelectedPages
.resize( 1 );
458 mSelectedPages
[0] = xDrawView
->getCurrentPage();
463 * Export all slides, or requested "PagePos"
465 if( mSelectedPages
.empty() )
467 uno::Reference
< drawing::XMasterPagesSupplier
> xMasterPagesSupplier( mxSrcDoc
, uno::UNO_QUERY
);
468 uno::Reference
< drawing::XDrawPagesSupplier
> xDrawPagesSupplier( mxSrcDoc
, uno::UNO_QUERY
);
470 if( xMasterPagesSupplier
.is() && xDrawPagesSupplier
.is() )
472 uno::Reference
< drawing::XDrawPages
> xMasterPages
= xMasterPagesSupplier
->getMasterPages();
473 uno::Reference
< drawing::XDrawPages
> xDrawPages
= xDrawPagesSupplier
->getDrawPages();
474 if( xMasterPages
.is() && xMasterPages
->getCount() &&
475 xDrawPages
.is() && xDrawPages
->getCount() )
477 sal_Int32 nDPCount
= xDrawPages
->getCount();
479 mSelectedPages
.resize( nPageToExport
!= -1 ? 1 : nDPCount
);
481 for( i
= 0; i
< nDPCount
; ++i
)
483 if( nPageToExport
!= -1 && nPageToExport
== i
)
485 uno::Reference
< drawing::XDrawPage
> xDrawPage( xDrawPages
->getByIndex( i
), uno::UNO_QUERY
);
486 mSelectedPages
[0] = xDrawPage
;
490 uno::Reference
< drawing::XDrawPage
> xDrawPage( xDrawPages
->getByIndex( i
), uno::UNO_QUERY
);
491 mSelectedPages
[i
] = xDrawPage
;
500 // #i124608# when selection only is wanted, get the current object selection
502 Reference
< view::XSelectionSupplier
> xSelection (xController
, UNO_QUERY
);
507 = ( xSelection
->getSelection() >>= maShapeSelection
);
511 if(bSelectionOnly
&& bGotSelection
&& 0 == maShapeSelection
->getCount())
513 // #i124608# export selection, got maShapeSelection but no shape selected -> nothing
514 // to export, we are done (maybe return true, but a hint that nothing was done
515 // may be useful; it may have happened by error)
521 * We get all master page that are targeted by at least one draw page.
522 * The master page are put in an unordered set.
524 ObjectSet aMasterPageTargetSet
;
525 for(const uno::Reference
<drawing::XDrawPage
> & mSelectedPage
: mSelectedPages
)
527 uno::Reference
< drawing::XMasterPageTarget
> xMasterPageTarget( mSelectedPage
, uno::UNO_QUERY
);
528 if( xMasterPageTarget
.is() )
530 aMasterPageTargetSet
.insert( xMasterPageTarget
->getMasterPage() );
533 // Later we move them to an uno::Sequence so we can get them by index
534 mMasterPageTargets
.resize( aMasterPageTargetSet
.size() );
536 for (auto const& masterPageTarget
: aMasterPageTargetSet
)
538 uno::Reference
< drawing::XDrawPage
> xMasterPage( masterPageTarget
, uno::UNO_QUERY
);
539 mMasterPageTargets
[i
++] = xMasterPage
;
542 bRet
= implExport( rDescriptor
);
549 pFocusWindow
->LeaveWait();
554 bool SVGFilter::filterWriterOrCalc( const Sequence
< PropertyValue
>& rDescriptor
)
556 bool bSelectionOnly
= false;
558 for (sal_Int32 nInd
= 0; nInd
< rDescriptor
.getLength(); nInd
++)
560 if (rDescriptor
[nInd
].Name
== "SelectionOnly")
562 rDescriptor
[nInd
].Value
>>= bSelectionOnly
;
567 if(!bSelectionOnly
) // For Writer only the selection-only mode is supported
570 uno::Reference
<frame::XDesktop2
> xDesktop(frame::Desktop::create(mxContext
));
571 uno::Reference
<frame::XController
> xController
;
572 if (xDesktop
->getCurrentFrame().is())
574 uno::Reference
<frame::XFrame
> xFrame(xDesktop
->getCurrentFrame(), uno::UNO_SET_THROW
);
575 xController
.set(xFrame
->getController(), uno::UNO_SET_THROW
);
578 Reference
< view::XSelectionSupplier
> xSelection (xController
, UNO_QUERY
);
579 if (!xSelection
.is())
582 // Select only one draw page
583 uno::Reference
< drawing::XDrawPagesSupplier
> xDrawPagesSupplier( mxSrcDoc
, uno::UNO_QUERY
);
584 uno::Reference
<drawing::XDrawPages
> xDrawPages
= xDrawPagesSupplier
->getDrawPages();
585 uno::Reference
< drawing::XDrawPage
> xDrawPage( xDrawPages
->getByIndex(0), uno::UNO_QUERY
);
586 mSelectedPages
.resize( 1 );
587 mSelectedPages
[0] = xDrawPage
;
589 bool bGotSelection
= xSelection
->getSelection() >>= maShapeSelection
;
595 // For Writer we might have a non-shape graphic
596 bGotSelection
= implExportWriterTextGraphic(xSelection
);
602 return implExport( rDescriptor
);
605 void SAL_CALL
SVGFilter::cancel( )
609 void SAL_CALL
SVGFilter::setSourceDocument( const Reference
< XComponent
>& xDoc
)
614 void SAL_CALL
SVGFilter::setTargetDocument( const Reference
< XComponent
>& xDoc
)
619 // There is already another SVG-Type_Detector, see
620 // vcl/source/filter/graphicfilter.cxx ("DOCTYPE svg"),
621 // but since these start from different preconditions it is not
622 // easy to unify these. For now, use this local helper.
626 const uno::Reference
<io::XInputStream
>& mxInput
;
627 uno::Sequence
< sal_Int8
> mnFirstBytes
;
628 sal_Int32 mnFirstBytesSize
;
629 sal_Int32 mnFirstRead
;
633 bool impCheckForMagic(
634 const sal_Int8
* pMagic
,
635 const sal_Int32 nMagicSize
)
637 const sal_Int8
* pBuffer(mnFirstBytes
.getConstArray());
640 pBuffer
+ mnFirstRead
,
642 pMagic
+ nMagicSize
) != pBuffer
+ mnFirstRead
;
645 void impEnsureProcessed()
659 if(0 == mnFirstBytesSize
)
664 mnFirstBytes
.realloc(mnFirstBytesSize
);
666 if(mnFirstBytesSize
!= mnFirstBytes
.getLength())
671 std::unique_ptr
< SvStream
> aStream(utl::UcbStreamHelper::CreateStream(mxInput
, true));
678 const sal_uLong
nStreamLen(aStream
->remainingSize());
680 if(aStream
->GetError())
685 mnFirstRead
= aStream
->ReadBytes(
687 std::min(nStreamLen
, sal_uLong(mnFirstBytesSize
)));
689 if(aStream
->GetError())
694 // check if it is gzipped -> svgz
695 if (mnFirstBytes
[0] == 0x1F && static_cast<sal_uInt8
>(mnFirstBytes
[1]) == 0x8B)
699 aCodec
.BeginCompression(ZCODEC_DEFAULT_COMPRESSION
, /*gzLib*/true);
700 mnFirstRead
= aCodec
.Read(
702 reinterpret_cast< sal_uInt8
* >(mnFirstBytes
.getArray()),
704 aCodec
.EndCompression();
712 const sal_Int8 aMagic
[] = {'<', 's', 'v', 'g'};
713 const sal_Int32
nMagicSize(SAL_N_ELEMENTS(aMagic
));
715 mbIsSVG
= impCheckForMagic(aMagic
, nMagicSize
);
720 const sal_Int8 aMagic
[] = {'D', 'O', 'C', 'T', 'Y', 'P', 'E', ' ', 's', 'v', 'g'};
721 const sal_Int32
nMagicSize(SAL_N_ELEMENTS(aMagic
));
723 mbIsSVG
= impCheckForMagic(aMagic
, nMagicSize
);
731 const uno::Reference
<io::XInputStream
>& xInput
)
734 mnFirstBytesSize(2048),
739 // For the default buffer size: Use not too big
740 // (not more than 16K), but also not too small
741 // (not less than 1/2K), see comments at
742 // ImpPeekGraphicFormat, SVG section.
743 // I remember these cases and it *can* happen
744 // that SVGs have quite massive comments in their
746 // Limit to plausible sizes, also for security reasons
747 mnFirstBytesSize
= std::min(sal_Int32(512), mnFirstBytesSize
);
748 mnFirstBytesSize
= std::max(sal_Int32(16384), mnFirstBytesSize
);
753 impEnsureProcessed();
760 impEnsureProcessed();
765 const sal_Int8 aMagic
[] = {'x', 'm', 'l', 'n', 's', ':', 'o', 'o', 'o'};
766 const sal_Int32
nMagicSize(SAL_N_ELEMENTS(aMagic
));
768 return impCheckForMagic(aMagic
, nMagicSize
);
776 impEnsureProcessed();
781 const sal_Int8 aMagic
[] = {'o', 'o', 'o', ':', 'm', 'e', 't', 'a', '_', 's', 'l', 'i', 'd', 'e', 's'};
782 const sal_Int32
nMagicSize(SAL_N_ELEMENTS(aMagic
));
784 return impCheckForMagic(aMagic
, nMagicSize
);
791 OUString SAL_CALL
SVGFilter::detect(Sequence
<PropertyValue
>& rDescriptor
)
793 utl::MediaDescriptor
aMediaDescriptor(rDescriptor
);
794 uno::Reference
<io::XInputStream
> xInput(aMediaDescriptor
[utl::MediaDescriptor::PROP_INPUTSTREAM()], UNO_QUERY
);
804 SVGFileInfo
aSVGFileInfo(xInput
);
806 if(aSVGFileInfo
.isSVG())
808 // We have SVG - set default document format to Draw
809 aRetval
= OUString(constFilterNameDraw
);
811 if(aSVGFileInfo
.isOwnFormat())
813 // it's a file that was written/exported by LO
814 if(aSVGFileInfo
.isImpress())
816 // it was written by Impress export. Set document
817 // format for import to Impress
818 aRetval
= OUString(constFilterName
);
823 catch (css::io::IOException
&)
825 TOOLS_WARN_EXCEPTION("filter.svg", "");
831 #define SVG_FILTER_IMPL_NAME "com.sun.star.comp.Draw.SVGFilter"
832 #define SVG_WRITER_IMPL_NAME "com.sun.star.comp.Draw.SVGWriter"
834 namespace sdecl
= comphelper::service_decl
;
835 sdecl::class_
<SVGFilter
> const serviceFilterImpl
;
836 const sdecl::ServiceDecl
svgFilter(
838 SVG_FILTER_IMPL_NAME
,
839 "com.sun.star.document.ImportFilter;"
840 "com.sun.star.document.ExportFilter;"
841 "com.sun.star.document.ExtendedTypeDetection" );
843 sdecl::class_
<SVGWriter
, sdecl::with_args
<true> > const serviceWriterImpl
;
844 const sdecl::ServiceDecl
svgWriter(
846 SVG_WRITER_IMPL_NAME
,
847 "com.sun.star.svg.SVGWriter" );
849 // The C shared lib entry points
850 extern "C" SAL_DLLPUBLIC_EXPORT
void* svgfilter_component_getFactory(
851 sal_Char
const* pImplName
, void*, void*)
853 if ( rtl_str_compare (pImplName
, SVG_FILTER_IMPL_NAME
) == 0 )
855 return sdecl::component_getFactoryHelper( pImplName
, {&svgFilter
} );
857 else if ( rtl_str_compare (pImplName
, SVG_WRITER_IMPL_NAME
) == 0 )
859 return sdecl::component_getFactoryHelper( pImplName
, {&svgWriter
} );
864 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */