LibreOffice Module xmloff (master) 1
XMLTextFrameContext.cxx
Go to the documentation of this file.
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 <o3tl/string_view.hxx>
21#include <osl/diagnose.h>
22#include <sal/log.hxx>
24#include <comphelper/base64.hxx>
25#include <com/sun/star/frame/XModel.hpp>
26#include <com/sun/star/lang/XMultiServiceFactory.hpp>
27#include <com/sun/star/text/TextContentAnchorType.hpp>
28#include <com/sun/star/beans/XPropertySet.hpp>
29#include <com/sun/star/text/XTextFrame.hpp>
30#include <com/sun/star/container/XNamed.hpp>
31#include <com/sun/star/container/XNameContainer.hpp>
32#include <com/sun/star/graphic/XGraphic.hpp>
33#include <com/sun/star/text/SizeType.hpp>
34#include <com/sun/star/drawing/XShape.hpp>
35#include <com/sun/star/document/XEventsSupplier.hpp>
36#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp>
37#include <com/sun/star/io/XOutputStream.hpp>
38#include <com/sun/star/text/HoriOrientation.hpp>
39#include <com/sun/star/text/VertOrientation.hpp>
41#include <utility>
42#include <xmloff/xmlimp.hxx>
43#include <xmloff/xmltoken.hxx>
46#include <xmloff/xmluconv.hxx>
51#include <xmloff/prstylei.hxx>
52#include <xmloff/i18nmap.hxx>
53#include <xexptran.hxx>
58#include <xmloff/attrlist.hxx>
65#include <map>
66#include <string_view>
67
68using namespace ::com::sun::star;
69using namespace ::com::sun::star::uno;
70using namespace ::com::sun::star::text;
71using namespace ::com::sun::star::xml::sax;
72using namespace ::com::sun::star::beans;
73using namespace ::com::sun::star::lang;
74using namespace ::com::sun::star::container;
75using namespace ::com::sun::star::drawing;
76using namespace ::com::sun::star::document;
77using namespace ::xmloff::token;
78using ::com::sun::star::document::XEventsSupplier;
79
80#define XML_TEXT_FRAME_TEXTBOX 1
81#define XML_TEXT_FRAME_GRAPHIC 2
82#define XML_TEXT_FRAME_OBJECT 3
83#define XML_TEXT_FRAME_OBJECT_OLE 4
84#define XML_TEXT_FRAME_APPLET 5
85#define XML_TEXT_FRAME_PLUGIN 6
86#define XML_TEXT_FRAME_FLOATING_FRAME 7
87
88typedef ::std::map < const OUString, OUString > ParamMap;
89
91{
92 OUString sHRef;
93 OUString sName;
95 bool bMap;
96
97public:
98
99 inline XMLTextFrameContextHyperlink_Impl( OUString aHRef,
100 OUString aName,
101 OUString aTargetFrameName,
102 bool bMap );
103
104 const OUString& GetHRef() const { return sHRef; }
105 const OUString& GetName() const { return sName; }
106 const OUString& GetTargetFrameName() const { return sTargetFrameName; }
107 bool GetMap() const { return bMap; }
108};
109
111 OUString aHRef, OUString aName,
112 OUString aTargetFrameName, bool bM ) :
113 sHRef(std::move( aHRef )),
114 sName(std::move( aName )),
115 sTargetFrameName(std::move( aTargetFrameName )),
116 bMap( bM )
117{
118}
119
120namespace {
121
122// Implement Title/Description Elements UI (#i73249#)
123class XMLTextFrameTitleOrDescContext_Impl : public SvXMLImportContext
124{
125 OUString& mrTitleOrDesc;
126
127public:
128
129
130 XMLTextFrameTitleOrDescContext_Impl( SvXMLImport& rImport,
131 OUString& rTitleOrDesc );
132
133 virtual void SAL_CALL characters( const OUString& rText ) override;
134};
135
136}
137
138XMLTextFrameTitleOrDescContext_Impl::XMLTextFrameTitleOrDescContext_Impl(
139 SvXMLImport& rImport,
140 OUString& rTitleOrDesc )
141 : SvXMLImportContext( rImport )
142 , mrTitleOrDesc( rTitleOrDesc )
143{
144}
145
146void XMLTextFrameTitleOrDescContext_Impl::characters( const OUString& rText )
147{
148 mrTitleOrDesc += rText;
149}
150
151namespace {
152
153class XMLTextFrameParam_Impl : public SvXMLImportContext
154{
155public:
156 XMLTextFrameParam_Impl( SvXMLImport& rImport,
157 const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList,
158 ParamMap &rParamMap);
159};
160
161}
162
163XMLTextFrameParam_Impl::XMLTextFrameParam_Impl(
164 SvXMLImport& rImport,
165 const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList,
166 ParamMap &rParamMap):
167 SvXMLImportContext( rImport )
168{
169 OUString sName, sValue;
170 bool bFoundValue = false; // to allow empty values
171 for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
172 {
173 switch (aIter.getToken())
174 {
175 case XML_ELEMENT(DRAW, XML_VALUE):
176 {
177 sValue = aIter.toString();
178 bFoundValue = true;
179 break;
180 }
181 case XML_ELEMENT(DRAW, XML_NAME):
182 sName = aIter.toString();
183 break;
184 default:
185 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
186 }
187 }
188 if (!sName.isEmpty() && bFoundValue )
189 rParamMap[sName] = sValue;
190}
191
192namespace {
193
194class XMLTextFrameContourContext_Impl : public SvXMLImportContext
195{
196 Reference < XPropertySet > xPropSet;
197
198public:
199
200
201 XMLTextFrameContourContext_Impl( SvXMLImport& rImport, sal_Int32 nElement,
202 const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList,
203 const Reference < XPropertySet >& rPropSet,
204 bool bPath );
205};
206
207}
208
209XMLTextFrameContourContext_Impl::XMLTextFrameContourContext_Impl(
210 SvXMLImport& rImport,
211 sal_Int32 /*nElement*/,
212 const Reference< XFastAttributeList > & xAttrList,
213 const Reference < XPropertySet >& rPropSet,
214 bool bPath ) :
215 SvXMLImportContext( rImport ),
216 xPropSet( rPropSet )
217{
218 OUString sD, sPoints, sViewBox;
219 bool bPixelWidth = false, bPixelHeight = false;
220 bool bAuto = false;
221 sal_Int32 nWidth = 0;
222 sal_Int32 nHeight = 0;
223
224 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
225 {
226 switch( aIter.getToken() )
227 {
228 case XML_ELEMENT(SVG, XML_VIEWBOX):
229 case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX):
230 sViewBox = aIter.toString();
231 break;
232 case XML_ELEMENT(SVG, XML_D):
233 case XML_ELEMENT(SVG_COMPAT, XML_D):
234 if( bPath )
235 sD = aIter.toString();
236 break;
237 case XML_ELEMENT(DRAW,XML_POINTS):
238 if( !bPath )
239 sPoints = aIter.toString();
240 break;
241 case XML_ELEMENT(SVG, XML_WIDTH):
242 case XML_ELEMENT(SVG_COMPAT, XML_WIDTH):
243 if (::sax::Converter::convertMeasurePx(nWidth, aIter.toView()))
244 bPixelWidth = true;
245 else
246 GetImport().GetMM100UnitConverter().convertMeasureToCore(
247 nWidth, aIter.toView());
248 break;
249 case XML_ELEMENT(SVG, XML_HEIGHT):
250 case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT):
251 if (::sax::Converter::convertMeasurePx(nHeight, aIter.toView()))
252 bPixelHeight = true;
253 else
254 GetImport().GetMM100UnitConverter().convertMeasureToCore(
255 nHeight, aIter.toView());
256 break;
258 bAuto = IsXMLToken(aIter, XML_TRUE);
259 break;
260 }
261 }
262
263 OUString sContourPolyPolygon("ContourPolyPolygon");
264 Reference < XPropertySetInfo > xPropSetInfo = rPropSet->getPropertySetInfo();
265
266 if(!xPropSetInfo->hasPropertyByName(sContourPolyPolygon) ||
267 nWidth <= 0 || nHeight <= 0 || bPixelWidth != bPixelHeight ||
268 !(bPath ? sD : sPoints).getLength())
269 return;
270
271 const SdXMLImExViewBox aViewBox( sViewBox, GetImport().GetMM100UnitConverter());
272 basegfx::B2DPolyPolygon aPolyPolygon;
273
274 if( bPath )
275 {
276 basegfx::utils::importFromSvgD(aPolyPolygon, sD, GetImport().needFixPositionAfterZ(), nullptr);
277 }
278 else
279 {
280 basegfx::B2DPolygon aPolygon;
281
282 if(basegfx::utils::importFromSvgPoints(aPolygon, sPoints))
283 {
284 aPolyPolygon = basegfx::B2DPolyPolygon(aPolygon);
285 }
286 }
287
288 if(aPolyPolygon.count())
289 {
290 const basegfx::B2DRange aSourceRange(
291 aViewBox.GetX(), aViewBox.GetY(),
292 aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight());
293 const basegfx::B2DRange aTargetRange(
294 0.0, 0.0,
295 nWidth, nHeight);
296
297 if(!aSourceRange.equal(aTargetRange))
298 {
299 aPolyPolygon.transform(
301 aSourceRange,
302 aTargetRange));
303 }
304
305 css::drawing::PointSequenceSequence aPointSequenceSequence;
306 basegfx::utils::B2DPolyPolygonToUnoPointSequenceSequence(aPolyPolygon, aPointSequenceSequence);
307 xPropSet->setPropertyValue( sContourPolyPolygon, Any(aPointSequenceSequence) );
308 }
309
310 static const OUStringLiteral sIsPixelContour(u"IsPixelContour");
311
312 if( xPropSetInfo->hasPropertyByName( sIsPixelContour ) )
313 {
314 xPropSet->setPropertyValue( sIsPixelContour, Any(bPixelWidth) );
315 }
316
317 static const OUStringLiteral sIsAutomaticContour(u"IsAutomaticContour");
318
319 if( xPropSetInfo->hasPropertyByName( sIsAutomaticContour ) )
320 {
321 xPropSet->setPropertyValue( sIsAutomaticContour, Any(bAuto) );
322 }
323}
324
325namespace {
326
327class XMLTextFrameContext_Impl : public SvXMLImportContext
328{
329 css::uno::Reference < css::text::XTextCursor > xOldTextCursor;
330 css::uno::Reference < css::beans::XPropertySet > xPropSet;
331 css::uno::Reference < css::io::XOutputStream > xBase64Stream;
332
334 bool mbListContextPushed;
335
336 OUString m_sOrigName;
337 OUString sName;
338 OUString sStyleName;
339 OUString sNextName;
340 OUString sHRef;
341 OUString sCode;
342 OUString sMimeType;
343 OUString sFrameName;
344 OUString sAppletName;
345 OUString sFilterService;
346 OUString sBase64CharsLeft;
347 OUString sTblName;
348 OUStringBuffer maUrlBuffer;
349
350 ParamMap aParamMap;
351
352 sal_Int32 nX;
353 sal_Int32 nY;
354 sal_Int32 nWidth;
355 sal_Int32 nHeight;
356 sal_Int32 nZIndex;
357 sal_Int16 nPage;
358 sal_Int16 nRotation;
359 sal_Int16 nRelWidth;
360 sal_Int16 nRelHeight;
361
362 sal_uInt16 nType;
363 css::text::TextContentAnchorType eAnchorType;
364
365 bool bMayScript : 1;
366 bool bMinWidth : 1;
367 bool bMinHeight : 1;
368 bool bSyncWidth : 1;
369 bool bSyncHeight : 1;
370 bool bCreateFailed : 1;
371 bool bOwnBase64Stream : 1;
372 bool mbMultipleContent : 1; // This context is created based on a multiple content (image)
373
374 void Create();
375
376public:
377
378
379 bool CreateIfNotThere();
380 const OUString& GetHRef() const { return sHRef; }
381
382 XMLTextFrameContext_Impl( SvXMLImport& rImport,
383 sal_Int32 nElement,
384 const css::uno::Reference<css::xml::sax::XFastAttributeList > & rAttrList,
385 css::text::TextContentAnchorType eAnchorType,
386 sal_uInt16 nType,
387 const css::uno::Reference<css::xml::sax::XFastAttributeList > & rFrameAttrList,
388 bool bMultipleContent = false );
389
390 virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
391
392 virtual void SAL_CALL characters( const OUString& rChars ) override;
393
394 virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
395 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
396
397 void SetHyperlink( const OUString& rHRef,
398 const OUString& rName,
399 const OUString& rTargetFrameName,
400 bool bMap );
401
402 // Implement Title/Description Elements UI (#i73249#)
403 void SetTitle( const OUString& rTitle );
404
405 void SetDesc( const OUString& rDesc );
406
407 void SetName();
408
409 const OUString& GetOrigName() const { return m_sOrigName; }
410
411 css::text::TextContentAnchorType GetAnchorType() const { return eAnchorType; }
412
413 const css::uno::Reference < css::beans::XPropertySet >& GetPropSet() const { return xPropSet; }
414};
415
416}
417
418void XMLTextFrameContext_Impl::Create()
419{
421 GetImport().GetTextImport();
422
423 switch ( nType)
424 {
427 if( xBase64Stream.is() )
428 {
429 OUString sURL( GetImport().ResolveEmbeddedObjectURLFromBase64() );
430 if( !sURL.isEmpty() )
431 xPropSet = GetImport().GetTextImport()
432 ->createAndInsertOLEObject( GetImport(), sURL,
433 sStyleName,
434 sTblName,
435 nWidth, nHeight );
436 }
437 else if( !sHRef.isEmpty() )
438 {
439 OUString sURL( GetImport().ResolveEmbeddedObjectURL( sHRef,
440 std::u16string_view() ) );
441
442 if( GetImport().IsPackageURL( sHRef ) )
443 {
444 xPropSet = GetImport().GetTextImport()
445 ->createAndInsertOLEObject( GetImport(), sURL,
446 sStyleName,
447 sTblName,
448 nWidth, nHeight );
449 }
450 else
451 {
452 // it should be an own OOo link that has no storage persistence
453 xPropSet = GetImport().GetTextImport()
454 ->createAndInsertOOoLink( GetImport(),
455 sURL,
456 sStyleName,
457 sTblName,
458 nWidth, nHeight );
459 }
460 }
461 else
462 {
463 OUString sURL = "vnd.sun.star.ServiceName:" + sFilterService;
464 xPropSet = GetImport().GetTextImport()
465 ->createAndInsertOLEObject( GetImport(), sURL,
466 sStyleName,
467 sTblName,
468 nWidth, nHeight );
469
470 }
471 break;
473 {
474 xPropSet = GetImport().GetTextImport()
475 ->createAndInsertApplet( sAppletName, sCode,
476 bMayScript, sHRef,
477 nWidth, nHeight);
478 break;
479 }
481 {
482 if(!sHRef.isEmpty())
483 GetImport().GetAbsoluteReference(sHRef);
484 xPropSet = GetImport().GetTextImport()
485 ->createAndInsertPlugin( sMimeType, sHRef,
486 nWidth, nHeight);
487
488 break;
489 }
491 {
492 xPropSet = GetImport().GetTextImport()
493 ->createAndInsertFloatingFrame( sFrameName, sHRef,
494 sStyleName,
495 nWidth, nHeight);
496 break;
497 }
498 default:
499 {
500 Reference<XMultiServiceFactory> xFactory( GetImport().GetModel(),
501 UNO_QUERY );
502 if( xFactory.is() )
503 {
504 OUString sServiceName;
505 switch( nType )
506 {
507 case XML_TEXT_FRAME_TEXTBOX: sServiceName = "com.sun.star.text.TextFrame"; break;
508 case XML_TEXT_FRAME_GRAPHIC: sServiceName = "com.sun.star.text.GraphicObject"; break;
509 }
510 Reference<XInterface> xIfc = xFactory->createInstance( sServiceName );
511 SAL_WARN_IF( !xIfc.is(), "xmloff.text", "couldn't create frame" );
512 if( xIfc.is() )
513 xPropSet.set( xIfc, UNO_QUERY );
514 }
515 }
516 }
517
518 if( !xPropSet.is() )
519 {
520 bCreateFailed = true;
521 return;
522 }
523
524 Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
525
526 // Skip duplicated frames
527 if(!mbMultipleContent && // It's allowed to have multiple image for the same frame
528 !sName.isEmpty() &&
529 xTextImportHelper->IsDuplicateFrame(sName, nX, nY, nWidth, nHeight))
530 {
531 bCreateFailed = true;
532 return;
533 }
534
535 // set name
536 Reference < XNamed > xNamed( xPropSet, UNO_QUERY );
537 if( xNamed.is() )
538 {
539 OUString sOrigName( xNamed->getName() );
540 if( sOrigName.isEmpty() ||
541 (!sName.isEmpty() && sOrigName != sName) )
542 {
543 OUString sOldName( sName );
544
545 sal_Int32 i = 0;
546 while( xTextImportHelper->HasFrameByName( sName ) )
547 {
548 sName = sOldName + OUString::number( ++i );
549 }
550 xNamed->setName( sName );
551 if( sName != sOldName )
552 {
553 xTextImportHelper->GetRenameMap().Add( XML_TEXT_RENAME_TYPE_FRAME,
554 sOldName, sName );
555
556 }
557 }
558 }
559
560 // frame style
561 XMLPropStyleContext *pStyle = nullptr;
562 if( !sStyleName.isEmpty() )
563 {
564 pStyle = xTextImportHelper->FindAutoFrameStyle( sStyleName );
565 if( pStyle )
566 sStyleName = pStyle->GetParentName();
567 }
568
569 Any aAny;
570 if( !sStyleName.isEmpty() )
571 {
572 OUString sDisplayStyleName( GetImport().GetStyleDisplayName(
573 XmlStyleFamily::SD_GRAPHICS_ID, sStyleName ) );
574 const Reference < XNameContainer > & rStyles =
575 xTextImportHelper->GetFrameStyles();
576 if( rStyles.is() &&
577 rStyles->hasByName( sDisplayStyleName ) )
578 {
579 xPropSet->setPropertyValue( "FrameStyleName", Any(sDisplayStyleName) );
580 }
581 }
582
583 // anchor type (must be set before any other properties, because
584 // otherwise some orientations cannot be set or will be changed
585 // afterwards)
586 xPropSet->setPropertyValue( "AnchorType", Any(eAnchorType) );
587
588 // hard properties
589 if( pStyle )
590 pStyle->FillPropertySet( xPropSet );
591
592 // x and y
593 sal_Int16 nHoriOrient = HoriOrientation::NONE;
594 aAny = xPropSet->getPropertyValue( "HoriOrient" );
595 aAny >>= nHoriOrient;
596 if( HoriOrientation::NONE == nHoriOrient )
597 {
598 xPropSet->setPropertyValue( "HoriOrientPosition", Any(nX) );
599 }
600
601 sal_Int16 nVertOrient = VertOrientation::NONE;
602 aAny = xPropSet->getPropertyValue( "VertOrient" );
603 aAny >>= nVertOrient;
604 if( VertOrientation::NONE == nVertOrient )
605 {
606 xPropSet->setPropertyValue( "VertOrientPosition", Any(nY) );
607 }
608
609 // width
610 if( nWidth > 0 )
611 {
612 xPropSet->setPropertyValue( "Width", Any(nWidth) );
613 }
614 if( nRelWidth > 0 || nWidth > 0 )
615 {
616 xPropSet->setPropertyValue( "RelativeWidth", Any(nRelWidth) );
617 }
618 if( bSyncWidth || nWidth > 0 )
619 {
620 xPropSet->setPropertyValue( "IsSyncWidthToHeight", Any(bSyncWidth) );
621 }
622 if( xPropSetInfo->hasPropertyByName( "WidthType" ) &&
623 (bMinWidth || nWidth > 0 || nRelWidth > 0 ) )
624 {
625 sal_Int16 nSizeType =
626 (bMinWidth && XML_TEXT_FRAME_TEXTBOX == nType) ? SizeType::MIN
627 : SizeType::FIX;
628 xPropSet->setPropertyValue( "WidthType", Any(nSizeType) );
629 }
630
631 if( nHeight > 0 )
632 {
633 xPropSet->setPropertyValue( "Height", Any(nHeight) );
634 }
635 if( nRelHeight > 0 || nHeight > 0 )
636 {
637 xPropSet->setPropertyValue( "RelativeHeight", Any(nRelHeight) );
638 }
639 if( bSyncHeight || nHeight > 0 )
640 {
641 xPropSet->setPropertyValue( "IsSyncHeightToWidth", Any(bSyncHeight) );
642 }
643 if( xPropSetInfo->hasPropertyByName( "SizeType" ) &&
644 (bMinHeight || nHeight > 0 || nRelHeight > 0 ) )
645 {
646 sal_Int16 nSizeType =
647 (bMinHeight && XML_TEXT_FRAME_TEXTBOX == nType) ? SizeType::MIN
648 : SizeType::FIX;
649 xPropSet->setPropertyValue( "SizeType", Any(nSizeType) );
650 }
651
652 if( XML_TEXT_FRAME_GRAPHIC == nType )
653 {
654 // URL
655 OSL_ENSURE( !sHRef.isEmpty() || xBase64Stream.is(),
656 "neither URL nor base64 image data given" );
657 uno::Reference<graphic::XGraphic> xGraphic;
658 if (!sHRef.isEmpty())
659 {
660 xGraphic = GetImport().loadGraphicByURL(sHRef);
661 }
662 else if (xBase64Stream.is())
663 {
664 xGraphic = GetImport().loadGraphicFromBase64(xBase64Stream);
665 xBase64Stream = nullptr;
666 }
667
668 if (xGraphic.is())
669 xPropSet->setPropertyValue("Graphic", Any(xGraphic));
670
671 // filter name
672 xPropSet->setPropertyValue( "GraphicFilter", Any(OUString()) );
673
674 // rotation
675 xPropSet->setPropertyValue( "GraphicRotation", Any(nRotation) );
676 }
677
678 // page number (must be set after the frame is inserted, because it
679 // will be overwritten then inserting the frame.
680 if( TextContentAnchorType_AT_PAGE == eAnchorType && nPage > 0 )
681 {
682 xPropSet->setPropertyValue( "AnchorPageNo", Any(nPage) );
683 }
684
685 if( XML_TEXT_FRAME_OBJECT != nType &&
686 XML_TEXT_FRAME_OBJECT_OLE != nType &&
687 XML_TEXT_FRAME_APPLET != nType &&
688 XML_TEXT_FRAME_PLUGIN!= nType &&
690 {
691 Reference < XTextContent > xTxtCntnt( xPropSet, UNO_QUERY );
692 try
693 {
694 xTextImportHelper->InsertTextContent(xTxtCntnt);
695 }
696 catch (lang::IllegalArgumentException const&)
697 {
698 TOOLS_WARN_EXCEPTION("xmloff.text", "Cannot import part of the text - probably an image in the text frame?");
699 return;
700 }
701 }
702
703 // Make adding the shape to Z-Ordering dependent from if we are
704 // inside an inside_deleted_section (redlining). That is necessary
705 // since the shape will be removed again later. It would lead to
706 // errors if it would stay inside the Z-Ordering. Thus, the
707 // easiest way to solve that conflict is to not add it here.
708 if(!GetImport().HasTextImport()
709 || !GetImport().GetTextImport()->IsInsideDeleteContext())
710 {
711 Reference < XShape > xShape( xPropSet, UNO_QUERY );
712
713 GetImport().GetShapeImport()->shapeWithZIndexAdded( xShape, nZIndex );
714 }
715
716 if( XML_TEXT_FRAME_TEXTBOX != nType )
717 return;
718
719 xTextImportHelper->ConnectFrameChains( sName, sNextName, xPropSet );
720 Reference < XTextFrame > xTxtFrame( xPropSet, UNO_QUERY );
721 Reference < XText > xTxt = xTxtFrame->getText();
722 xOldTextCursor = xTextImportHelper->GetCursor();
723 xTextImportHelper->SetCursor( xTxt->createTextCursor() );
724
725 // remember old list item and block (#89892#) and reset them
726 // for the text frame
727 xTextImportHelper->PushListContext();
728 mbListContextPushed = true;
729}
730
732{
733 const XMLTextFrameContext_Impl* pXMLTextFrameContext_Impl = dynamic_cast< const XMLTextFrameContext_Impl* >(&rContext);
734
735 if(!pXMLTextFrameContext_Impl)
736 return;
737
738 try
739 {
740 // just dispose to delete
741 uno::Reference< lang::XComponent > xComp(pXMLTextFrameContext_Impl->GetPropSet(), UNO_QUERY);
742
743 // Inform shape importer about the removal so it can adjust
744 // z-indexes.
745 uno::Reference<drawing::XShape> xShape(xComp, uno::UNO_QUERY);
746 GetImport().GetShapeImport()->shapeRemoved(xShape);
747
748 if(xComp.is())
749 {
750 xComp->dispose();
751 }
752 }
753 catch( uno::Exception& )
754 {
755 OSL_FAIL( "Error in cleanup of multiple graphic object import (!)" );
756 }
757}
758
760{
761 const XMLTextFrameContext_Impl* pXMLTextFrameContext_Impl = dynamic_cast< const XMLTextFrameContext_Impl* >(&rContext);
762
763 if(pXMLTextFrameContext_Impl)
764 {
765 return "vnd.sun.star.Package:" + pXMLTextFrameContext_Impl->GetHRef();
766 }
767
768 return OUString();
769}
770
771css::uno::Reference<css::graphic::XGraphic> XMLTextFrameContext::getGraphicFromImportContext(const SvXMLImportContext& rContext) const
772{
773 uno::Reference<graphic::XGraphic> xGraphic;
774
775 const XMLTextFrameContext_Impl* pXMLTextFrameContext_Impl = dynamic_cast<const XMLTextFrameContext_Impl*>(&rContext);
776
777 if (pXMLTextFrameContext_Impl)
778 {
779 try
780 {
781 const uno::Reference<beans::XPropertySet>& xPropertySet = pXMLTextFrameContext_Impl->GetPropSet();
782
783 if (xPropertySet.is())
784 {
785 xPropertySet->getPropertyValue("Graphic") >>= xGraphic;
786 }
787 }
788 catch (uno::Exception&)
789 {}
790 }
791 return xGraphic;
792}
793
794bool XMLTextFrameContext_Impl::CreateIfNotThere()
795{
796 if( !xPropSet.is() &&
797 ( XML_TEXT_FRAME_OBJECT_OLE == nType ||
798 XML_TEXT_FRAME_GRAPHIC == nType ) &&
799 xBase64Stream.is() && !bCreateFailed )
800 {
801 if( bOwnBase64Stream )
802 xBase64Stream->closeOutput();
803 Create();
804 }
805
806 return xPropSet.is();
807}
808
809XMLTextFrameContext_Impl::XMLTextFrameContext_Impl(
810 SvXMLImport& rImport,
811 sal_Int32 /*nElement*/,
812 const Reference< XFastAttributeList > & rAttrList,
813 TextContentAnchorType eATyp,
814 sal_uInt16 nNewType,
815 const Reference< XFastAttributeList > & rFrameAttrList,
816 bool bMultipleContent )
817: SvXMLImportContext( rImport )
818, mbListContextPushed( false )
819, nType( nNewType )
820, eAnchorType( eATyp )
821{
822 nX = 0;
823 nY = 0;
824 nWidth = 0;
825 nHeight = 0;
826 nZIndex = -1;
827 nPage = 0;
828 nRotation = 0;
829 nRelWidth = 0;
830 nRelHeight = 0;
831 bMayScript = false;
832
833 bMinHeight = false;
834 bMinWidth = false;
835 bSyncWidth = false;
836 bSyncHeight = false;
837 bCreateFailed = false;
838 bOwnBase64Stream = false;
839 mbMultipleContent = bMultipleContent;
840
841 auto processAttr = [&](sal_Int32 nElement, const sax_fastparser::FastAttributeList::FastAttributeIter& aIter) -> void
842 {
843 switch( nElement )
844 {
845 case XML_ELEMENT(DRAW, XML_STYLE_NAME):
846 sStyleName = aIter.toString();
847 break;
848 case XML_ELEMENT(DRAW, XML_NAME):
849 m_sOrigName = aIter.toString();
850 sName = m_sOrigName;
851 break;
852 case XML_ELEMENT(DRAW, XML_FRAME_NAME):
853 sFrameName = aIter.toString();
854 break;
855 case XML_ELEMENT(DRAW, XML_APPLET_NAME):
856 sAppletName = aIter.toString();
857 break;
858 case XML_ELEMENT(TEXT, XML_ANCHOR_TYPE):
859 if( TextContentAnchorType_AT_PARAGRAPH == eAnchorType ||
860 TextContentAnchorType_AT_CHARACTER == eAnchorType ||
861 TextContentAnchorType_AS_CHARACTER == eAnchorType )
862 {
863
864 TextContentAnchorType eNew;
865 if( XMLAnchorTypePropHdl::convert( aIter.toView(), eNew ) &&
866 ( TextContentAnchorType_AT_PARAGRAPH == eNew ||
867 TextContentAnchorType_AT_CHARACTER == eNew ||
868 TextContentAnchorType_AS_CHARACTER == eNew ||
869 TextContentAnchorType_AT_PAGE == eNew) )
870 eAnchorType = eNew;
871 }
872 break;
874 {
875 sal_Int32 nTmp;
876 if (::sax::Converter::convertNumber(nTmp, aIter.toView(), 1, SHRT_MAX))
877 nPage = static_cast<sal_Int16>(nTmp);
878 }
879 break;
880 case XML_ELEMENT(SVG, XML_X):
881 case XML_ELEMENT(SVG_COMPAT, XML_X):
882 GetImport().GetMM100UnitConverter().convertMeasureToCore(
883 nX, aIter.toView());
884 break;
885 case XML_ELEMENT(SVG, XML_Y):
886 case XML_ELEMENT(SVG_COMPAT, XML_Y):
887 GetImport().GetMM100UnitConverter().convertMeasureToCore(
888 nY, aIter.toView() );
889 break;
890 case XML_ELEMENT(SVG, XML_WIDTH):
891 case XML_ELEMENT(SVG_COMPAT, XML_WIDTH):
892 // relative widths are obsolete since SRC617. Remove them some day!
893 if( aIter.toView().find( '%' ) != std::string_view::npos )
894 {
895 sal_Int32 nTmp;
896 if (::sax::Converter::convertPercent(nTmp, aIter.toView()))
897 nRelWidth = static_cast<sal_Int16>(nTmp);
898 }
899 else
900 {
902 nWidth, aIter.toView(), 0 );
903 }
904 break;
905 case XML_ELEMENT(STYLE, XML_REL_WIDTH):
906 if( IsXMLToken(aIter, XML_SCALE) )
907 {
908 bSyncWidth = true;
909 }
910 else
911 {
912 sal_Int32 nTmp;
913 if (::sax::Converter::convertPercent( nTmp, aIter.toView() ))
914 nRelWidth = static_cast<sal_Int16>(nTmp);
915 }
916 break;
917 case XML_ELEMENT(FO, XML_MIN_WIDTH):
918 case XML_ELEMENT(FO_COMPAT, XML_MIN_WIDTH):
919 if( aIter.toView().find( '%' ) != std::string_view::npos )
920 {
921 sal_Int32 nTmp;
922 if (::sax::Converter::convertPercent(nTmp, aIter.toView()))
923 nRelWidth = static_cast<sal_Int16>(nTmp);
924 }
925 else
926 {
928 nWidth, aIter.toView(), 0 );
929 }
930 bMinWidth = true;
931 break;
932 case XML_ELEMENT(SVG, XML_HEIGHT):
933 case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT):
934 // relative heights are obsolete since SRC617. Remove them some day!
935 if( aIter.toView().find( '%' ) != std::string_view::npos )
936 {
937 sal_Int32 nTmp;
938 if (::sax::Converter::convertPercent(nTmp, aIter.toView()))
939 nRelHeight = static_cast<sal_Int16>(nTmp);
940 }
941 else
942 {
944 nHeight, aIter.toView(), 0 );
945 }
946 break;
947 case XML_ELEMENT(STYLE, XML_REL_HEIGHT):
948 if( IsXMLToken( aIter, XML_SCALE ) )
949 {
950 bSyncHeight = true;
951 }
952 else if( IsXMLToken( aIter, XML_SCALE_MIN ) )
953 {
954 bSyncHeight = true;
955 bMinHeight = true;
956 }
957 else
958 {
959 sal_Int32 nTmp;
960 if (::sax::Converter::convertPercent( nTmp, aIter.toView() ))
961 nRelHeight = static_cast<sal_Int16>(nTmp);
962 }
963 break;
964 case XML_ELEMENT(FO, XML_MIN_HEIGHT):
965 case XML_ELEMENT(FO_COMPAT, XML_MIN_HEIGHT):
966 if( aIter.toView().find( '%' ) != std::string_view::npos )
967 {
968 sal_Int32 nTmp;
969 if (::sax::Converter::convertPercent(nTmp, aIter.toView()))
970 nRelHeight = static_cast<sal_Int16>(nTmp);
971 }
972 else
973 {
975 nHeight, aIter.toView(), 0 );
976 }
977 bMinHeight = true;
978 break;
979 case XML_ELEMENT(DRAW, XML_ZINDEX):
980 ::sax::Converter::convertNumber( nZIndex, aIter.toView(), -1 );
981 break;
983 sNextName = aIter.toString();
984 break;
985 case XML_ELEMENT(XLINK, XML_HREF):
986 sHRef = aIter.toString();
987 break;
988 case XML_ELEMENT(DRAW, XML_TRANSFORM):
989 {
990 // RotateFlyFrameFix: im/export full 'draw:transform' using existing tooling
991 // Currently only rotation is used, but combinations with 'draw:transform'
992 // may be necessary in the future, so that svg:x/svg:y/svg:width/svg:height
993 // may be extended/replaced with 'draw:transform' (see draw objects)
994 SdXMLImExTransform2D aSdXMLImExTransform2D;
995 basegfx::B2DHomMatrix aFullTransform;
996
997 // Use SdXMLImExTransform2D to convert to transformation
998 // Note: using GetTwipUnitConverter instead of GetMM100UnitConverter may be needed,
999 // but is not generally available (as it should be, a 'current' UnitConverter should
1000 // be available at GetExport() - and maybe was once). May have to be addressed as soon
1001 // as translate transformations are used here.
1002 aSdXMLImExTransform2D.SetString(aIter.toString(), GetImport().GetMM100UnitConverter());
1003 aSdXMLImExTransform2D.GetFullTransform(aFullTransform);
1004
1005 if(!aFullTransform.isIdentity())
1006 {
1007 const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomposedTransform(aFullTransform);
1008
1009 // currently we *only* use rotation (and translation indirectly), so warn if *any*
1010 // of the other transform parts is used
1011 SAL_WARN_IF(!basegfx::fTools::equal(1.0, aDecomposedTransform.getScale().getX()), "xmloff.text", "draw:transform uses scaleX" );
1012 SAL_WARN_IF(!basegfx::fTools::equal(1.0, aDecomposedTransform.getScale().getY()), "xmloff.text", "draw:transform uses scaleY" );
1013 SAL_WARN_IF(!basegfx::fTools::equalZero(aDecomposedTransform.getShearX()), "xmloff.text", "draw:transform uses shearX" );
1014
1015 // Translation comes from the translate to RotCenter, rot and BackTranslate.
1016 // This means that it represents the translation between unrotated TopLeft
1017 // and rotated TopLeft. This may be checked here now, but currently we only
1018 // use rotation around center and assume that this *was* a rotation around
1019 // center. The check would compare the object's center with the RotCenter
1020 // that can be extracted from the transformation in aFullTransform.
1021 // The definition contains implicitly the RotationCenter absolute
1022 // to the scaled and translated object, so this may be used if needed (see
1023 // _exportTextGraphic how the -trans/rot/trans is composed)
1024
1025 if(!basegfx::fTools::equalZero(aDecomposedTransform.getRotate()))
1026 {
1027 // rotation is used, set it. Convert from deg to 10th degree integer
1028 // CAUTION: due to #i78696# (rotation mirrored using API) the rotate
1029 // value is already mirrored, so do not do it again here (to be in sync
1030 // with XMLTextParagraphExport::_exportTextGraphic normally it would need
1031 // to me mirrored using * -1.0, see conversion there)
1032 // CAUTION-II: due to tdf#115782 it is better for current ODF to indeed use it
1033 // with the wrong orientation as in all other cases - ARGH! We will need to
1034 // correct this in future ODF ASAP! For now, mirror the rotation here AGAIN
1035 const double fRotate(-basegfx::rad2deg<10>(aDecomposedTransform.getRotate()));
1036 nRotation = static_cast< sal_Int16 >(basegfx::fround(fRotate) % 3600);
1037
1038 // tdf#115529 may be negative, with the above modulo maximal -3599, so
1039 // no loop needed here. nRotation is used in setPropertyValue("GraphicRotation")
1040 // and *has* to be in the range [0 .. 3600[
1041 if(nRotation < 0)
1042 {
1043 nRotation += 3600;
1044 }
1045 }
1046 }
1047 }
1048 break;
1049 case XML_ELEMENT(DRAW, XML_CODE):
1050 sCode = aIter.toString();
1051 break;
1052 case XML_ELEMENT(DRAW, XML_OBJECT):
1053 break;
1054 case XML_ELEMENT(DRAW, XML_ARCHIVE):
1055 break;
1056 case XML_ELEMENT(DRAW, XML_MAY_SCRIPT):
1057 bMayScript = IsXMLToken( aIter, XML_TRUE );
1058 break;
1059 case XML_ELEMENT(DRAW, XML_MIME_TYPE):
1060 case XML_ELEMENT(LO_EXT, XML_MIME_TYPE):
1061 sMimeType = aIter.toString();
1062 break;
1065 sTblName = aIter.toString();
1066 break;
1067 default:
1068 SAL_INFO("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << " value=" << aIter.toString());
1069 }
1070 };
1071
1072 for( auto& aIter : sax_fastparser::castToFastAttributeList(rAttrList) )
1073 processAttr(aIter.getToken(), aIter);
1074 for( auto& aIter : sax_fastparser::castToFastAttributeList(rFrameAttrList) )
1075 processAttr(aIter.getToken(), aIter);
1076
1077 if( ( (XML_TEXT_FRAME_GRAPHIC == nType ||
1078 XML_TEXT_FRAME_OBJECT == nType ||
1079 XML_TEXT_FRAME_OBJECT_OLE == nType) &&
1080 sHRef.isEmpty() ) ||
1081 ( XML_TEXT_FRAME_APPLET == nType && sCode.isEmpty() ) ||
1082 ( XML_TEXT_FRAME_PLUGIN == nType &&
1083 sHRef.isEmpty() && sMimeType.isEmpty() ) )
1084 return; // no URL: no image or OLE object
1085
1086 Create();
1087}
1088
1089void XMLTextFrameContext_Impl::endFastElement(sal_Int32 )
1090{
1091 if( ( XML_TEXT_FRAME_OBJECT_OLE == nType ||
1092 XML_TEXT_FRAME_GRAPHIC == nType) &&
1093 !xPropSet.is() && !bCreateFailed )
1094 {
1095 std::u16string_view sTrimmedChars = o3tl::trim(maUrlBuffer);
1096 if( !sTrimmedChars.empty() )
1097 {
1098 if( !xBase64Stream.is() )
1099 {
1100 if( XML_TEXT_FRAME_GRAPHIC == nType )
1101 {
1102 xBase64Stream =
1103 GetImport().GetStreamForGraphicObjectURLFromBase64();
1104 }
1105 else
1106 {
1107 xBase64Stream =
1108 GetImport().GetStreamForEmbeddedObjectURLFromBase64();
1109 }
1110 if( xBase64Stream.is() )
1111 bOwnBase64Stream = true;
1112 }
1113 if( bOwnBase64Stream && xBase64Stream.is() )
1114 {
1115 OUString sChars;
1116 if( !sBase64CharsLeft.isEmpty() )
1117 {
1118 sChars = sBase64CharsLeft + sTrimmedChars;
1119 sBase64CharsLeft.clear();
1120 }
1121 else
1122 {
1123 sChars = sTrimmedChars;
1124 }
1125 Sequence< sal_Int8 > aBuffer( (sChars.getLength() / 4) * 3 );
1126 sal_Int32 nCharsDecoded =
1127 ::comphelper::Base64::decodeSomeChars( aBuffer, sChars );
1128 xBase64Stream->writeBytes( aBuffer );
1129 if( nCharsDecoded != sChars.getLength() )
1130 sBase64CharsLeft = sChars.copy( nCharsDecoded );
1131 }
1132 }
1133 maUrlBuffer.setLength(0);
1134 }
1135
1136 CreateIfNotThere();
1137
1138 if( xOldTextCursor.is() )
1139 {
1140 GetImport().GetTextImport()->DeleteParagraph();
1141 GetImport().GetTextImport()->SetCursor( xOldTextCursor );
1142 }
1143
1144 // reinstall old list item (if necessary) #89892#
1145 if (mbListContextPushed) {
1146 GetImport().GetTextImport()->PopListContext();
1147 }
1148
1149 if (( nType == XML_TEXT_FRAME_APPLET || nType == XML_TEXT_FRAME_PLUGIN ) && xPropSet.is())
1150 GetImport().GetTextImport()->endAppletOrPlugin( xPropSet, aParamMap);
1151}
1152
1153css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextFrameContext_Impl::createFastChildContext(
1154 sal_Int32 nElement,
1155 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
1156{
1157 if( nElement == XML_ELEMENT(DRAW, XML_PARAM) )
1158 {
1159 if ( nType == XML_TEXT_FRAME_APPLET || nType == XML_TEXT_FRAME_PLUGIN )
1160 return new XMLTextFrameParam_Impl( GetImport(),
1161 xAttrList, aParamMap );
1162 }
1163 else if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) )
1164 {
1165 if( !xPropSet.is() && !xBase64Stream.is() && !bCreateFailed )
1166 {
1167 switch( nType )
1168 {
1170 xBase64Stream =
1171 GetImport().GetStreamForGraphicObjectURLFromBase64();
1172 break;
1174 xBase64Stream =
1175 GetImport().GetStreamForEmbeddedObjectURLFromBase64();
1176 break;
1177 }
1178 if( xBase64Stream.is() )
1179 return new XMLBase64ImportContext( GetImport(), xBase64Stream );
1180 }
1181 }
1182 // Correction of condition which also avoids warnings. (#i100480#)
1183 if( XML_TEXT_FRAME_OBJECT == nType &&
1184 ( nElement == XML_ELEMENT(OFFICE, XML_DOCUMENT) ||
1185 nElement == XML_ELEMENT(MATH, XML_MATH) ) )
1186 {
1187 if( !xPropSet.is() && !bCreateFailed )
1188 {
1190 new XMLEmbeddedObjectImportContext( GetImport(), nElement, xAttrList );
1191 sFilterService = pEContext->GetFilterServiceName();
1192 if( !sFilterService.isEmpty() )
1193 {
1194 Create();
1195 if( xPropSet.is() )
1196 {
1197 Reference < XEmbeddedObjectSupplier > xEOS( xPropSet,
1198 UNO_QUERY );
1199 OSL_ENSURE( xEOS.is(),
1200 "no embedded object supplier for own object" );
1201 Reference<css::lang::XComponent> aXComponent(xEOS->getEmbeddedObject());
1202 pEContext->SetComponent( aXComponent );
1203 }
1204 }
1205 return pEContext;
1206 }
1207 }
1208
1209 if( xOldTextCursor.is() ) // text-box
1210 {
1211 auto p = GetImport().GetTextImport()->CreateTextChildContext(
1212 GetImport(), nElement, xAttrList,
1214 if (p)
1215 return p;
1216 }
1217
1218 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
1219
1220 return nullptr;
1221}
1222
1223void XMLTextFrameContext_Impl::characters( const OUString& rChars )
1224{
1225 maUrlBuffer.append(rChars);
1226}
1227
1228void XMLTextFrameContext_Impl::SetHyperlink( const OUString& rHRef,
1229 const OUString& rName,
1230 const OUString& rTargetFrameName,
1231 bool bMap )
1232{
1233 static constexpr OUStringLiteral s_HyperLinkURL = u"HyperLinkURL";
1234 static constexpr OUStringLiteral s_HyperLinkName = u"HyperLinkName";
1235 static constexpr OUStringLiteral s_HyperLinkTarget = u"HyperLinkTarget";
1236 static constexpr OUStringLiteral s_ServerMap = u"ServerMap";
1237 if( !xPropSet.is() )
1238 return;
1239
1240 Reference < XPropertySetInfo > xPropSetInfo =
1241 xPropSet->getPropertySetInfo();
1242 if( !xPropSetInfo.is() ||
1243 !xPropSetInfo->hasPropertyByName(s_HyperLinkURL))
1244 return;
1245
1246 xPropSet->setPropertyValue( s_HyperLinkURL, Any(rHRef) );
1247
1248 if (xPropSetInfo->hasPropertyByName(s_HyperLinkName))
1249 {
1250 xPropSet->setPropertyValue(s_HyperLinkName, Any(rName));
1251 }
1252
1253 if (xPropSetInfo->hasPropertyByName(s_HyperLinkTarget))
1254 {
1255 xPropSet->setPropertyValue( s_HyperLinkTarget, Any(rTargetFrameName) );
1256 }
1257
1258 if (xPropSetInfo->hasPropertyByName(s_ServerMap))
1259 {
1260 xPropSet->setPropertyValue(s_ServerMap, Any(bMap));
1261 }
1262}
1263
1264void XMLTextFrameContext_Impl::SetName()
1265{
1266 Reference<XNamed> xNamed(xPropSet, UNO_QUERY);
1267 if (m_sOrigName.isEmpty() || !xNamed.is())
1268 return;
1269
1270 OUString const name(xNamed->getName());
1271 if (name != m_sOrigName)
1272 {
1273 try
1274 {
1275 xNamed->setName(m_sOrigName);
1276 }
1277 catch (uno::Exception const&)
1278 { // fdo#71698 document contains 2 frames with same draw:name
1279 TOOLS_INFO_EXCEPTION("xmloff.text", "SetName(): exception setting \""
1280 << m_sOrigName << "\"");
1281 }
1282 }
1283}
1284
1285// Implement Title/Description Elements UI (#i73249#)
1286void XMLTextFrameContext_Impl::SetTitle( const OUString& rTitle )
1287{
1288 if ( xPropSet.is() )
1289 {
1290 Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1291 if( xPropSetInfo->hasPropertyByName( "Title" ) )
1292 {
1293 xPropSet->setPropertyValue( "Title", Any( rTitle ) );
1294 }
1295 }
1296}
1297
1298void XMLTextFrameContext_Impl::SetDesc( const OUString& rDesc )
1299{
1300 if ( xPropSet.is() )
1301 {
1302 Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
1303 if( xPropSetInfo->hasPropertyByName( "Description" ) )
1304 {
1305 xPropSet->setPropertyValue( "Description", Any( rDesc ) );
1306 }
1307 }
1308}
1309
1310
1311bool XMLTextFrameContext::CreateIfNotThere( css::uno::Reference < css::beans::XPropertySet >& rPropSet )
1312{
1313 SvXMLImportContext *pContext = m_xImplContext.get();
1314 XMLTextFrameContext_Impl *pImpl = dynamic_cast< XMLTextFrameContext_Impl*>( pContext );
1315 if( pImpl && pImpl->CreateIfNotThere() )
1316 rPropSet = pImpl->GetPropSet();
1317
1318 return rPropSet.is();
1319}
1320
1322 SvXMLImport& rImport,
1323 const Reference< XFastAttributeList > & xAttrList,
1324 TextContentAnchorType eATyp )
1325: SvXMLImportContext( rImport )
1326, m_xAttrList( new sax_fastparser::FastAttributeList( xAttrList ) )
1327 // Implement Title/Description Elements UI (#i73249#)
1328, m_eDefaultAnchorType( eATyp )
1329 // Shapes in Writer cannot be named via context menu (#i51726#)
1330, m_HasAutomaticStyleWithoutParentStyle( false )
1331, m_bSupportsReplacement( false )
1332{
1333 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
1334 {
1335 // New distinguish attribute between Writer objects and Draw objects is:
1336 // Draw objects have an automatic style without a parent style (#i51726#)
1337 switch (aIter.getToken())
1338 {
1339 case XML_ELEMENT(DRAW, XML_STYLE_NAME):
1340 {
1341 OUString aStyleName = aIter.toString();
1342 if( !aStyleName.isEmpty() )
1343 {
1346 XMLPropStyleContext* pStyle = xTxtImport->FindAutoFrameStyle( aStyleName );
1347 if ( pStyle && pStyle->GetParentName().isEmpty() )
1348 {
1350 }
1351 }
1352 break;
1353 }
1354 case XML_ELEMENT(TEXT, XML_ANCHOR_TYPE):
1355 {
1356 TextContentAnchorType eNew;
1357 if( XMLAnchorTypePropHdl::convert( aIter.toView(), eNew ) &&
1358 ( TextContentAnchorType_AT_PARAGRAPH == eNew ||
1359 TextContentAnchorType_AT_CHARACTER == eNew ||
1360 TextContentAnchorType_AS_CHARACTER == eNew ||
1361 TextContentAnchorType_AT_PAGE == eNew) )
1362 m_eDefaultAnchorType = eNew;
1363 break;
1364 }
1365 }
1366 }
1367}
1368
1370{
1372 SvXMLImportContextRef const pMultiContext(solveMultipleImages());
1373
1374 SvXMLImportContext const*const pContext =
1375 (pMultiContext.is()) ? pMultiContext.get() : m_xImplContext.get();
1376 XMLTextFrameContext_Impl *pImpl = const_cast<XMLTextFrameContext_Impl*>(dynamic_cast< const XMLTextFrameContext_Impl*>( pContext ));
1377 assert(!pMultiContext.is() || pImpl);
1378
1379 // When we are dealing with a textbox, pImpl will be null;
1380 // we need to set the hyperlink to the shape instead
1381 Reference<XShape> xShape = GetShape();
1382 if (xShape.is() && m_pHyperlink)
1383 {
1384 Reference<XPropertySet> xProps(xShape, UNO_QUERY);
1385 if (xProps.is())
1386 xProps->setPropertyValue("Hyperlink", Any(m_pHyperlink->GetHRef()));
1387 }
1388
1389 if( !pImpl )
1390 return;
1391
1392 pImpl->CreateIfNotThere();
1393
1394 // fdo#68839: in case the surviving image was not the first one,
1395 // it will have a counter added to its name - set the original name
1396 if (pMultiContext.is()) // do this only when necessary; esp. not for text
1397 { // frames that may have entries in GetRenameMap()!
1398 pImpl->SetName();
1399 }
1400
1401 if( !m_sTitle.isEmpty() )
1402 {
1403 pImpl->SetTitle( m_sTitle );
1404 }
1405 if( !m_sDesc.isEmpty() )
1406 {
1407 pImpl->SetDesc( m_sDesc );
1408 }
1409
1410 if( m_pHyperlink )
1411 {
1412 pImpl->SetHyperlink( m_pHyperlink->GetHRef(), m_pHyperlink->GetName(),
1413 m_pHyperlink->GetTargetFrameName(), m_pHyperlink->GetMap() );
1414 m_pHyperlink.reset();
1415 }
1416
1417 GetImport().GetTextImport()->StoreLastImportedFrameName(pImpl->GetOrigName());
1418}
1419
1420css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextFrameContext::createFastChildContext(
1421 sal_Int32 nElement,
1422 const uno::Reference< xml::sax::XFastAttributeList>& xAttrList )
1423{
1424 SvXMLImportContextRef xContext;
1425
1426 if( !m_xImplContext.is() )
1427 {
1428 // no child exists
1429 if( IsTokenInNamespace(nElement, XML_NAMESPACE_DRAW) )
1430 {
1431 sal_uInt16 nFrameType = USHRT_MAX;
1432 switch (nElement & TOKEN_MASK)
1433 {
1434 case XML_TEXT_BOX:
1435 nFrameType = XML_TEXT_FRAME_TEXTBOX;
1436 break;
1437 case XML_IMAGE:
1438 nFrameType = XML_TEXT_FRAME_GRAPHIC;
1439 break;
1440 case XML_OBJECT:
1441 nFrameType = XML_TEXT_FRAME_OBJECT;
1442 break;
1443 case XML_OBJECT_OLE:
1444 nFrameType = XML_TEXT_FRAME_OBJECT_OLE;
1445 break;
1446 case XML_APPLET:
1447 nFrameType = XML_TEXT_FRAME_APPLET;
1448 break;
1449 case XML_PLUGIN:
1450 nFrameType = XML_TEXT_FRAME_PLUGIN;
1451 break;
1452 case XML_FLOATING_FRAME:
1453 nFrameType = XML_TEXT_FRAME_FLOATING_FRAME;
1454 break;
1455 }
1456
1457 if( USHRT_MAX != nFrameType )
1458 {
1459 // Shapes in Writer cannot be named via context menu (#i51726#)
1460 if ( ( XML_TEXT_FRAME_TEXTBOX == nFrameType ||
1461 XML_TEXT_FRAME_GRAPHIC == nFrameType ) &&
1463 {
1464 Reference < XShapes > xShapes;
1466 GetImport(), nElement, xAttrList, xShapes, m_xAttrList );
1467 }
1468 else if( XML_TEXT_FRAME_PLUGIN == nFrameType )
1469 {
1470 bool bMedia = false;
1471
1472 // check, if we have a media object
1473 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
1474 {
1475 if( aIter.getToken() == XML_ELEMENT(DRAW, XML_MIME_TYPE) )
1476 {
1477 if( aIter.toView() == "application/vnd.sun.star.media" )
1478 bMedia = true;
1479
1480 // leave this loop
1481 break;
1482 }
1483 }
1484
1485 if( bMedia )
1486 {
1487 Reference < XShapes > xShapes;
1489 GetImport(), nElement, xAttrList, xShapes, m_xAttrList );
1490 }
1491 }
1492 else if( XML_TEXT_FRAME_OBJECT == nFrameType ||
1493 XML_TEXT_FRAME_OBJECT_OLE == nFrameType )
1494 {
1496 }
1497 else if(XML_TEXT_FRAME_GRAPHIC == nFrameType)
1498 {
1500 }
1501
1502 if (!xContext)
1503 {
1504 xContext = new XMLTextFrameContext_Impl( GetImport(), nElement,
1505 xAttrList,
1507 nFrameType,
1508 m_xAttrList );
1509 }
1510
1511 m_xImplContext = xContext;
1512
1514 {
1516 }
1517 }
1518 }
1519 }
1520 else if(getSupportsMultipleContents() && nElement == XML_ELEMENT(DRAW, XML_IMAGE))
1521 {
1522 // read another image
1523 xContext = new XMLTextFrameContext_Impl(
1524 GetImport(), nElement, xAttrList,
1526
1527 m_xImplContext = xContext;
1529 }
1530 else if( m_bSupportsReplacement && !m_xReplImplContext.is() &&
1531 nElement == XML_ELEMENT(DRAW, XML_IMAGE) )
1532 {
1533 // read replacement image
1534 Reference < XPropertySet > xPropSet;
1535 if( CreateIfNotThere( xPropSet ) )
1536 {
1537 xContext = new XMLReplacementImageContext( GetImport(),
1538 nElement, xAttrList, xPropSet );
1539 m_xReplImplContext = xContext;
1540 }
1541 }
1542 else if( nullptr != dynamic_cast< const XMLTextFrameContext_Impl*>( m_xImplContext.get() ))
1543 {
1544 // the child is a writer frame
1545 if( IsTokenInNamespace(nElement, XML_NAMESPACE_SVG) ||
1547 {
1548 // Implement Title/Description Elements UI (#i73249#)
1549 const bool bOld = SvXMLImport::OOo_2x >= GetImport().getGeneratorVersion();
1550 if ( bOld )
1551 {
1552 if ( (nElement & TOKEN_MASK) == XML_DESC )
1553 {
1554 xContext = new XMLTextFrameTitleOrDescContext_Impl( GetImport(),
1555 m_sTitle );
1556 }
1557 }
1558 else
1559 {
1560 if( (nElement & TOKEN_MASK) == XML_TITLE )
1561 {
1563 { // tdf#103567 ensure props are set on surviving shape
1565 }
1566 xContext = new XMLTextFrameTitleOrDescContext_Impl( GetImport(),
1567 m_sTitle );
1568 }
1569 else if ( (nElement & TOKEN_MASK) == XML_DESC )
1570 {
1572 { // tdf#103567 ensure props are set on surviving shape
1574 }
1575 xContext = new XMLTextFrameTitleOrDescContext_Impl( GetImport(),
1576 m_sDesc );
1577 }
1578 }
1579 }
1580 else if( IsTokenInNamespace(nElement, XML_NAMESPACE_DRAW) )
1581 {
1582 Reference < XPropertySet > xPropSet;
1583 if( (nElement & TOKEN_MASK) == XML_CONTOUR_POLYGON )
1584 {
1586 { // tdf#103567 ensure props are set on surviving shape
1588 }
1589 if( CreateIfNotThere( xPropSet ) )
1590 xContext = new XMLTextFrameContourContext_Impl( GetImport(), nElement,
1591 xAttrList, xPropSet, false );
1592 }
1593 else if( (nElement & TOKEN_MASK) == XML_CONTOUR_PATH )
1594 {
1596 { // tdf#103567 ensure props are set on surviving shape
1598 }
1599 if( CreateIfNotThere( xPropSet ) )
1600 xContext = new XMLTextFrameContourContext_Impl( GetImport(), nElement,
1601 xAttrList, xPropSet, true );
1602 }
1603 else if( (nElement & TOKEN_MASK) == XML_IMAGE_MAP )
1604 {
1606 { // tdf#103567 ensure props are set on surviving shape
1608 }
1609 if( CreateIfNotThere( xPropSet ) )
1610 xContext = new XMLImageMapContext( GetImport(), xPropSet );
1611 }
1612 }
1613 else if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) )
1614 {
1616 { // tdf#103567 ensure props are set on surviving shape
1618 }
1619 // do we still have the frame object?
1620 Reference < XPropertySet > xPropSet;
1621 if( CreateIfNotThere( xPropSet ) )
1622 {
1623 // is it an event supplier?
1624 Reference<XEventsSupplier> xEventsSupplier(xPropSet, UNO_QUERY);
1625 if (xEventsSupplier.is())
1626 {
1627 // OK, we have the events, so create the context
1628 xContext = new XMLEventsImportContext(GetImport(), xEventsSupplier);
1629 }
1630 }
1631 }
1632 }
1633 // #i68101#
1634 else if( nElement == XML_ELEMENT(SVG, XML_TITLE) || nElement == XML_ELEMENT(SVG, XML_DESC ) ||
1635 nElement == XML_ELEMENT(SVG_COMPAT, XML_TITLE) || nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC ) )
1636 {
1638 { // tdf#103567 ensure props are set on surviving shape
1639 // note: no more draw:image can be added once we get here
1641 }
1642 xContext = static_cast<SvXMLImportContext*>(m_xImplContext->createFastChildContext( nElement, xAttrList ).get());
1643 }
1644 else if (nElement == XML_ELEMENT(LO_EXT, XML_SIGNATURELINE))
1645 {
1647 { // tdf#103567 ensure props are set on surviving shape
1648 // note: no more draw:image can be added once we get here
1650 }
1651 xContext = static_cast<SvXMLImportContext*>(m_xImplContext->createFastChildContext(nElement, xAttrList).get());
1652 }
1653 else if (nElement == XML_ELEMENT(LO_EXT, XML_QRCODE))
1654 {
1656 { // tdf#103567 ensure props are set on surviving shape
1657 // note: no more draw:image can be added once we get here
1659 }
1660 xContext = static_cast<SvXMLImportContext*>(m_xImplContext->createFastChildContext(nElement, xAttrList).get());
1661 }
1662 else if (nElement == XML_ELEMENT(DRAW, XML_A))
1663 {
1664 xContext = static_cast<SvXMLImportContext*>(m_xImplContext->createFastChildContext(nElement, xAttrList).get());
1665 }
1666 else
1667 {
1668 // the child is a drawing shape
1670 m_xImplContext.get(), nElement, xAttrList );
1671 }
1672
1673 return xContext;
1674}
1675
1676void XMLTextFrameContext::SetHyperlink( const OUString& rHRef,
1677 const OUString& rName,
1678 const OUString& rTargetFrameName,
1679 bool bMap )
1680{
1681 OSL_ENSURE( !m_pHyperlink, "recursive SetHyperlink call" );
1682 m_pHyperlink = std::make_unique<XMLTextFrameContextHyperlink_Impl>(
1683 rHRef, rName, rTargetFrameName, bMap );
1684}
1685
1686TextContentAnchorType XMLTextFrameContext::GetAnchorType() const
1687{
1688 SvXMLImportContext *pContext = m_xImplContext.get();
1689 XMLTextFrameContext_Impl *pImpl = dynamic_cast< XMLTextFrameContext_Impl*>( pContext );
1690 if( pImpl )
1691 return pImpl->GetAnchorType();
1692 else
1693 return m_eDefaultAnchorType;
1694}
1695
1696Reference < XTextContent > XMLTextFrameContext::GetTextContent() const
1697{
1698 Reference < XTextContent > xTxtCntnt;
1699 SvXMLImportContext *pContext = m_xImplContext.get();
1700 XMLTextFrameContext_Impl *pImpl = dynamic_cast< XMLTextFrameContext_Impl* >( pContext );
1701 if( pImpl )
1702 xTxtCntnt.set( pImpl->GetPropSet(), UNO_QUERY );
1703
1704 return xTxtCntnt;
1705}
1706
1707Reference < XShape > XMLTextFrameContext::GetShape() const
1708{
1709 Reference < XShape > xShape;
1710 SvXMLImportContext* pContext = m_xImplContext.get();
1711 SvXMLShapeContext* pImpl = dynamic_cast<SvXMLShapeContext*>( pContext );
1712 if ( pImpl )
1713 {
1714 xShape = pImpl->getShape();
1715 }
1716
1717 return xShape;
1718}
1719
1720/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define XML_TEXT_FRAME_PLUGIN
#define XML_TEXT_FRAME_FLOATING_FRAME
#define XML_TEXT_FRAME_OBJECT_OLE
#define XML_TEXT_FRAME_APPLET
#define XML_TEXT_FRAME_TEXTBOX
#define XML_TEXT_FRAME_GRAPHIC
::std::map< const OUString, OUString > ParamMap
#define XML_TEXT_FRAME_OBJECT
constexpr OUStringLiteral sServiceName
constexpr OUStringLiteral sFrameName
bool getSupportsMultipleContents() const
read/write access to boolean switch
SvXMLImportContextRef solveMultipleImages()
solve multiple imported images.
void setSupportsMultipleContents(bool bNew)
void addContent(const SvXMLImportContext &rSvXMLImportContext)
add a content to the remembered image import contexts
void SetString(const OUString &rNew, const SvXMLUnitConverter &rConv)
Definition: xexptran.cxx:349
void GetFullTransform(::basegfx::B2DHomMatrix &rFullTrans)
Definition: xexptran.cxx:482
This class deliberately does not support XWeak, to improve performance when loading large documents.
Definition: xmlictxt.hxx:48
virtual void SAL_CALL endFastElement(sal_Int32 Element) override
endFastElement is called before a context will be destructed, but after an elements context has been ...
Definition: xmlictxt.cxx:40
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:60
virtual css::uno::Reference< XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > &Attribs) override
Definition: xmlictxt.cxx:59
virtual void SAL_CALL characters(const OUString &aChars) override
This method is called for all characters that are contained in the current element.
Definition: xmlictxt.cxx:70
rtl::Reference< XMLShapeImportHelper > const & GetShapeImport()
Definition: xmlimp.hxx:610
const SvXMLUnitConverter & GetMM100UnitConverter() const
Definition: xmlimp.hxx:401
static OUString getPrefixAndNameFromToken(sal_Int32 nToken)
Definition: xmlimp.cxx:1957
sal_uInt16 getGeneratorVersion() const
this checks the build ID and returns
Definition: xmlimp.cxx:1847
rtl::Reference< XMLTextImportHelper > const & GetTextImport()
Definition: xmlimp.hxx:602
static const sal_uInt16 OOo_2x
Definition: xmlimp.hxx:537
const css::uno::Reference< css::drawing::XShape > & getShape() const
const OUString & GetParentName() const
Definition: xmlstyle.hxx:81
bool convertMeasureToCore(sal_Int32 &rValue, std::u16string_view rString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32) const
convert string to measure with meCoreMeasureUnit, using optional min and max values
Definition: xmluconv.cxx:187
static bool convert(std::string_view rStrImpValue, css::text::TextContentAnchorType &rType)
Definition: txtprhdl.cxx:651
void SetComponent(css::uno::Reference< css::lang::XComponent > const &rComp)
Import <script:events> element.
virtual void FillPropertySet(const css::uno::Reference< css::beans::XPropertySet > &rPropSet)
Definition: prstylei.cxx:222
static SvXMLShapeContext * CreateFrameChildContext(SvXMLImport &rImport, sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, css::uno::Reference< css::drawing::XShapes > const &rShapes, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xFrameAttrList)
rtl::Reference< sax_fastparser::FastAttributeList > m_xAttrList
css::text::TextContentAnchorType GetAnchorType() const
css::uno::Reference< css::text::XTextContent > GetTextContent() const
css::text::TextContentAnchorType m_eDefaultAnchorType
std::unique_ptr< XMLTextFrameContextHyperlink_Impl > m_pHyperlink
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &AttrList) override
OUString getGraphicPackageURLFromImportContext(const SvXMLImportContext &rContext) const override
void SetHyperlink(const OUString &rHRef, const OUString &rName, const OUString &rTargetFrameName, bool bMap)
css::uno::Reference< css::graphic::XGraphic > getGraphicFromImportContext(const SvXMLImportContext &rContext) const override
XMLTextFrameContext(SvXMLImport &rImport, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, css::text::TextContentAnchorType eDfltAnchorType)
virtual void SAL_CALL endFastElement(sal_Int32 nElement) override
endFastElement is called before a context will be destructed, but after an elements context has been ...
bool CreateIfNotThere(css::uno::Reference< css::beans::XPropertySet > &rPropSet)
SvXMLImportContextRef m_xImplContext
css::uno::Reference< css::drawing::XShape > GetShape() const
void removeGraphicFromImportContext(const SvXMLImportContext &rContext) override
helper to get the created xShape instance, needs to be overridden
SvXMLImportContextRef m_xReplImplContext
bool isIdentity() const
void transform(const basegfx::B2DHomMatrix &rMatrix)
sal_uInt32 count() const
static std::size_t decodeSomeChars(css::uno::Sequence< sal_Int8 > &aPass, std::u16string_view sBuffer)
static bool convertPercent(sal_Int32 &rValue, std::u16string_view rString)
static bool convertNumber(sal_Int32 &rValue, std::u16string_view aString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32)
#define TOOLS_WARN_EXCEPTION(area, stream)
#define TOOLS_INFO_EXCEPTION(area, stream)
virtual void SetTitle(const OUString &rNewTitle) override
float u
Reference< XSingleServiceFactory > xFactory
DRAW
const char * name
OUString aName
void * p
#define SAL_WARN_IF(condition, area, stream)
#define SAL_INFO(area, stream)
if(aStr !=aBuf) UpdateName_Impl(m_xFollowLb.get()
const char * sName
bool equalZero(const T &rfVal)
bool equal(T const &rfValA, T const &rfValB)
bool importFromSvgPoints(B2DPolygon &o_rPoly, std::u16string_view rSvgPointsAttribute)
void B2DPolyPolygonToUnoPointSequenceSequence(const B2DPolyPolygon &rPolyPolygon, css::drawing::PointSequenceSequence &rPointSequenceSequenceRetval)
bool importFromSvgD(B2DPolyPolygon &o_rPolyPoly, std::u16string_view rSvgDAttribute, bool bHandleRelativeNextPointCompatible, PointIndexSet *pHelpPointIndexSet)
B2DHomMatrix createSourceRangeTargetRangeTransform(const B2DRange &rSourceRange, const B2DRange &rTargetRange)
B2IRange fround(const B2DRange &rRange)
OSQLColumns::const_iterator find(const OSQLColumns::const_iterator &first, const OSQLColumns::const_iterator &last, std::u16string_view _rVal, const ::comphelper::UStringMixEqual &_rCase)
int i
void Create(SwFormatVertOrient &rItem, SvStream &rStrm, sal_uInt16 nVersionAbusedAsSize)
std::u16string_view trim(std::u16string_view str)
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
OUString toString(OptionInfo const *info)
Handling of tokens in XML:
@ XML_NOTIFY_ON_UPDATE_OF_TABLE
Definition: xmltoken.hxx:2210
@ XML_NOTIFY_ON_UPDATE_OF_RANGES
Definition: xmltoken.hxx:2256
@ XML_ANCHOR_PAGE_NUMBER
Definition: xmltoken.hxx:247
bool IsXMLToken(std::u16string_view rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3583
QPRO_FUNC_TYPE nType
#define XML_TEXT_RENAME_TYPE_FRAME
Definition: txtimp.hxx:91
@ TextBox
Definition: txtimp.hxx:73
std::unique_ptr< char[]> aBuffer
static void convertNumber(OUStringBuffer &b, sal_Int32 n)
#define XMLOFF_WARN_UNKNOWN_ELEMENT(area, token)
Definition: xmlictxt.hxx:120
#define XMLOFF_WARN_UNKNOWN(area, rIter)
Definition: xmlictxt.hxx:114
#define XML_ELEMENT(prefix, name)
Definition: xmlimp.hxx:98
constexpr bool IsTokenInNamespace(sal_Int32 nToken, sal_uInt16 nNamespacePrefix)
Definition: xmlimp.hxx:105
constexpr sal_Int32 TOKEN_MASK
Definition: xmlimp.hxx:95
constexpr sal_uInt16 XML_NAMESPACE_DRAW
constexpr sal_uInt16 XML_NAMESPACE_SVG
constexpr sal_uInt16 XML_NAMESPACE_SVG_COMPAT