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 .
20 #include "GraphicHelpers.hxx"
21 #include "TagLogger.hxx"
22 #include <dmapper/GraphicZOrderHelper.hxx>
23 #include "PropertyIds.hxx"
25 #include <ooxml/resourceids.hxx>
27 #include <com/sun/star/text/HoriOrientation.hpp>
28 #include <com/sun/star/text/VertOrientation.hpp>
29 #include <com/sun/star/text/RelOrientation.hpp>
31 #include <oox/drawingml/drawingmltypes.hxx>
32 #include <sal/log.hxx>
33 #include <svx/dialmgr.hxx>
34 #include <svx/strings.hrc>
35 #include <comphelper/diagnose_ex.hxx>
39 namespace writerfilter::dmapper
{
41 using namespace com::sun::star
;
43 PositionHandler::PositionHandler( std::pair
<OUString
, OUString
>& rPositionOffsets
, std::pair
<OUString
, OUString
>& rAligns
) :
44 LoggedProperties("PositionHandler"),
45 m_nOrient(text::VertOrientation::NONE
),
46 m_nRelation(text::RelOrientation::FRAME
),
48 m_rPositionOffsets(rPositionOffsets
),
53 PositionHandler::~PositionHandler( )
57 void PositionHandler::lcl_attribute( Id aName
, Value
& rVal
)
59 sal_Int32 nIntValue
= rVal
.getInt( );
62 case NS_ooxml::LN_CT_PosV_relativeFrom
:
66 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_margin
:
67 m_nRelation
= text::RelOrientation::PAGE_PRINT_AREA
;
70 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_page
:
71 m_nRelation
= text::RelOrientation::PAGE_FRAME
;
74 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_topMargin
:
75 m_nRelation
= text::RelOrientation::PAGE_PRINT_AREA_TOP
;
78 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_bottomMargin
:
79 m_nRelation
= text::RelOrientation::PAGE_PRINT_AREA_BOTTOM
;
82 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_paragraph
:
83 m_nRelation
= text::RelOrientation::FRAME
;
86 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_line
:
87 m_nRelation
= text::RelOrientation::TEXT_LINE
;
90 // TODO There are some other unhandled values
92 SAL_WARN("writerfilter", "unhandled case (" << nIntValue
<< ") in NS_ooxml::LN_CT_PosV_relativeFrom");
97 case NS_ooxml::LN_CT_PosH_relativeFrom
:
101 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_margin
:
102 m_nRelation
= text::RelOrientation::PAGE_PRINT_AREA
;
105 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_page
:
106 m_nRelation
= text::RelOrientation::PAGE_FRAME
;
109 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_insideMargin
:
110 m_nRelation
= text::RelOrientation::PAGE_FRAME
;
111 m_bPageToggle
= true;
114 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_column
:
115 m_nRelation
= text::RelOrientation::FRAME
;
118 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_character
:
119 m_nRelation
= text::RelOrientation::CHAR
;
122 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_leftMargin
:
123 m_nRelation
= text::RelOrientation::PAGE_LEFT
;
126 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_rightMargin
:
127 m_nRelation
= text::RelOrientation::PAGE_RIGHT
;
130 // TODO There are some other unhandled values
132 SAL_WARN("writerfilter", "unhandled case (" << nIntValue
<< ") in NS_ooxml::LN_CT_PosH_relativeFrom");
138 TagLogger::getInstance().element("unhandled");
144 void PositionHandler::lcl_sprm(Sprm
& rSprm
)
146 sal_uInt32 nSprmId
= rSprm
.getId();
150 case NS_ooxml::LN_CT_PosH_posOffset
:
151 m_nPosition
= oox::drawingml::convertEmuToHmm(m_rPositionOffsets
.first
.toInt32());
152 m_rPositionOffsets
.first
.clear();
154 case NS_ooxml::LN_CT_PosV_posOffset
:
155 m_nPosition
= oox::drawingml::convertEmuToHmm(m_rPositionOffsets
.second
.toInt32());
156 m_rPositionOffsets
.second
.clear();
158 case NS_ooxml::LN_CT_PosH_align
:
160 OUString
& rAlign
= m_rAligns
.first
;
161 if (rAlign
== "left")
162 m_nOrient
= text::HoriOrientation::LEFT
;
163 else if (rAlign
== "right")
164 m_nOrient
= text::HoriOrientation::RIGHT
;
165 else if (rAlign
== "center")
166 m_nOrient
= text::HoriOrientation::CENTER
;
167 else if (rAlign
== "inside")
168 m_nOrient
= text::HoriOrientation::INSIDE
;
169 else if (rAlign
== "outside")
170 m_nOrient
= text::HoriOrientation::OUTSIDE
;
174 case NS_ooxml::LN_CT_PosV_align
:
176 OUString
& rAlign
= m_rAligns
.second
;
178 m_nOrient
= text::VertOrientation::TOP
;
179 else if (rAlign
== "bottom")
180 m_nOrient
= text::VertOrientation::BOTTOM
;
181 else if (rAlign
== "center")
182 m_nOrient
= text::VertOrientation::CENTER
;
183 else if (rAlign
== "inside" && m_nRelation
== text::RelOrientation::PAGE_PRINT_AREA_BOTTOM
)
184 m_nOrient
= text::VertOrientation::TOP
;
185 else if (rAlign
== "outside" && m_nRelation
== text::RelOrientation::PAGE_PRINT_AREA_BOTTOM
)
186 m_nOrient
= text::VertOrientation::BOTTOM
;
193 sal_Int16
PositionHandler::orientation() const
195 if( m_nRelation
== text::RelOrientation::TEXT_LINE
)
196 { // It appears that to 'line of text' alignment is backwards to other alignments,
197 // 'top' meaning putting on top of the line instead of having top at the line.
198 if( m_nOrient
== text::VertOrientation::TOP
)
199 return text::VertOrientation::BOTTOM
;
200 else if( m_nOrient
== text::VertOrientation::BOTTOM
)
201 return text::VertOrientation::TOP
;
206 WrapHandler::WrapHandler( ) :
207 LoggedProperties("WrapHandler"),
213 WrapHandler::~WrapHandler( )
217 void WrapHandler::lcl_attribute( Id aName
, Value
& rVal
)
221 case NS_ooxml::LN_CT_Wrap_type
:
222 m_nType
= sal_Int32( rVal
.getInt( ) );
224 case NS_ooxml::LN_CT_Wrap_side
:
225 m_nSide
= sal_Int32( rVal
.getInt( ) );
231 void WrapHandler::lcl_sprm( Sprm
& )
235 text::WrapTextMode
WrapHandler::getWrapMode( ) const
237 // The wrap values do not map directly to our wrap mode,
238 // e.g. none in .docx actually means through in LO.
239 text::WrapTextMode nMode
= text::WrapTextMode_THROUGH
;
243 case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_square
:
244 // through and tight are somewhat complicated, approximate
245 case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_tight
:
246 case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_through
:
250 case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapSide_left
:
251 nMode
= text::WrapTextMode_LEFT
;
253 case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapSide_right
:
254 nMode
= text::WrapTextMode_RIGHT
;
257 nMode
= text::WrapTextMode_PARALLEL
;
261 case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_topAndBottom
:
262 nMode
= text::WrapTextMode_NONE
;
264 case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_none
:
266 nMode
= text::WrapTextMode_THROUGH
;
273 void GraphicZOrderHelper::addItem(uno::Reference
<beans::XPropertySet
> const& props
, sal_Int32
const relativeHeight
)
275 m_items
[ relativeHeight
] = props
;
278 // The relativeHeight value in .docx is an arbitrary number, where only the relative ordering matters.
279 // But in Writer, the z-order is index in 0..(numitems-1) range, so whenever a new item needs to be
280 // added in the proper z-order, it is necessary to find the proper index.
281 sal_Int32
GraphicZOrderHelper::findZOrder( sal_Int32 relativeHeight
, bool bOldStyle
)
283 // std::map is iterated sorted by key
284 auto it
= std::find_if(m_items
.cbegin(), m_items
.cend(),
285 [relativeHeight
, bOldStyle
](const Items::value_type
& rItem
) {
286 // Old-style ordering differs in what should happen when there is already an item with the same z-order:
287 // we belong under it in case of new-style, but we belong above it in case of old-style.
288 return bOldStyle
? (rItem
.first
> relativeHeight
) : (rItem
.first
>= relativeHeight
);
291 sal_Int32
itemZOrderOffset(0); // before the item
292 if( it
== m_items
.end()) // we're topmost
297 itemZOrderOffset
= 1; // after the topmost
299 // Check if this shape has a textbox. If so, the textbox will have its own ZOrder, so
300 // suggest a larger offset.
301 bool bTextBox
= false;
302 uno::Reference
<beans::XPropertySet
> xShape
= it
->second
;
303 uno::Reference
<beans::XPropertySetInfo
> xInfo
= xShape
->getPropertySetInfo();
304 if (xInfo
->hasPropertyByName("TextBox"))
306 xShape
->getPropertyValue("TextBox") >>= bTextBox
;
313 // SwXFrame::getPropertyValue throws uno::RuntimeException
314 // when its GetFrameFormat() returns nullptr
316 sal_Int32
itemZOrder(0);
317 if( it
->second
->getPropertyValue(getPropertyName( PROP_Z_ORDER
)) >>= itemZOrder
)
318 return itemZOrder
+ itemZOrderOffset
;
320 catch (const uno::RuntimeException
&) {
321 TOOLS_WARN_EXCEPTION("writerfilter", "Exception when getting item z-order");
323 SAL_WARN( "writerfilter", "findZOrder() didn't find item z-order" );
324 return 0; // this should not(?) happen
327 ExtentHandler::ExtentHandler()
331 ExtentHandler::~ExtentHandler()
335 void ExtentHandler::attribute(Id nName
, Value
& rValue
)
337 sal_Int32 nIntValue
= rValue
.getInt();
340 case NS_ooxml::LN_CT_PositiveSize2D_cx
:
342 m_Extent
.Width
= nIntValue
;
345 case NS_ooxml::LN_CT_PositiveSize2D_cy
:
347 m_Extent
.Height
= nIntValue
;
355 void ExtentHandler::sprm(Sprm
& rSprm
)
357 sal_uInt32 nSprmId
= rSprm
.getId();
360 case NS_ooxml::LN_CT_Inline_extent
:
361 case NS_ooxml::LN_CT_Anchor_extent
:
363 writerfilter::Reference
<Properties
>::Pointer_t pProperties
= rSprm
.getProps();
366 pProperties
->resolve(*this);
376 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */