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 <sdr/contact/viewcontactofgraphic.hxx>
21 #include <sdr/contact/viewobjectcontactofgraphic.hxx>
22 #include <svx/svdograf.hxx>
23 #include <svx/sdr/primitive2d/sdrattributecreator.hxx>
24 #include <svl/itemset.hxx>
26 #include <svx/sdgcpitm.hxx>
27 #include <svx/sdr/contact/displayinfo.hxx>
28 #include <svx/sdr/contact/viewobjectcontact.hxx>
29 #include <svx/sdr/contact/objectcontact.hxx>
30 #include <basegfx/matrix/b2dhommatrix.hxx>
31 #include <sdr/primitive2d/sdrgrafprimitive2d.hxx>
32 #include "svx/svdstr.hrc"
33 #include <svdglob.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/settings.hxx>
36 #include <basegfx/polygon/b2dpolygontools.hxx>
37 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
38 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
39 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
40 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
41 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
42 #include <sdr/primitive2d/sdrtextprimitive2d.hxx>
43 #include <editeng/eeitem.hxx>
44 #include <editeng/colritem.hxx>
45 #include <basegfx/matrix/b2dhommatrixtools.hxx>
46 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
48 #include "eventhandler.hxx"
49 #include "bitmaps.hlst"
55 // Create a Object-Specific ViewObjectContact, set ViewContact and
56 // ObjectContact. Always needs to return something.
57 ViewObjectContact
& ViewContactOfGraphic::CreateObjectSpecificViewObjectContact(ObjectContact
& rObjectContact
)
59 ViewObjectContact
* pRetval
= new ViewObjectContactOfGraphic(rObjectContact
, *this);
60 DBG_ASSERT(pRetval
, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
65 ViewContactOfGraphic::ViewContactOfGraphic(SdrGrafObj
& rGrafObj
)
66 : ViewContactOfTextObj(rGrafObj
)
70 ViewContactOfGraphic::~ViewContactOfGraphic()
74 void ViewContactOfGraphic::flushGraphicObjects()
76 // #i102380# The graphic is swapped out. To let that have an effect, it is necessary to
77 // delete copies of the GraphicObject which are not swapped out and have no SwapHandler set
78 // (this is what happens when the GraphicObject gets copied to a SdrGrafPrimitive2D). This
79 // is best achieved for the VC by clearing the local decomposition cache. It would be possible
80 // to also do this for the VOC cache, but that VOCs exist exactly express that the object
81 // gets visualised, so this would be wrong.
82 flushViewIndependentPrimitive2DSequence();
85 drawinglayer::primitive2d::Primitive2DContainer
ViewContactOfGraphic::createVIP2DSForPresObj(
86 const basegfx::B2DHomMatrix
& rObjectMatrix
,
87 const drawinglayer::attribute::SdrLineFillShadowTextAttribute
& rAttribute
) const
89 drawinglayer::primitive2d::Primitive2DContainer xRetval
;
90 GraphicObject aEmptyGraphicObject
;
91 GraphicAttr aEmptyGraphicAttr
;
93 // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts
94 const drawinglayer::primitive2d::Primitive2DReference
xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
99 xRetval
= drawinglayer::primitive2d::Primitive2DContainer
{ xReferenceA
};
101 // SdrGrafPrimitive2D with content (which is the preview graphic) scaled to smaller size and
102 // without attributes
103 basegfx::B2DHomMatrix aSmallerMatrix
;
105 // #i94431# for some reason, i forgot to take the PrefMapMode of the graphic
106 // into account. Since EmptyPresObj's are only used in Draw/Impress, it is
107 // safe to assume 100th mm as target.
108 Size
aPrefSize(GetGrafObject().GetGrafPrefSize());
110 if(MapUnit::MapPixel
== GetGrafObject().GetGrafPrefMapMode().GetMapUnit())
112 aPrefSize
= Application::GetDefaultDevice()->PixelToLogic(aPrefSize
, MapUnit::Map100thMM
);
116 aPrefSize
= OutputDevice::LogicToLogic(aPrefSize
, GetGrafObject().GetGrafPrefMapMode(), MapUnit::Map100thMM
);
119 // decompose object matrix to get single values
120 basegfx::B2DVector aScale
, aTranslate
;
121 double fRotate
, fShearX
;
122 rObjectMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
124 const double fOffsetX((aScale
.getX() - aPrefSize
.getWidth()) / 2.0);
125 const double fOffsetY((aScale
.getY() - aPrefSize
.getHeight()) / 2.0);
127 if(basegfx::fTools::moreOrEqual(fOffsetX
, 0.0) && basegfx::fTools::moreOrEqual(fOffsetY
, 0.0))
129 // create the EmptyPresObj fallback visualisation. The fallback graphic
130 // is already provided in rGraphicObject in this case, use it
131 aSmallerMatrix
= basegfx::tools::createScaleTranslateB2DHomMatrix(aPrefSize
.getWidth(), aPrefSize
.getHeight(), fOffsetX
, fOffsetY
);
132 aSmallerMatrix
= basegfx::tools::createShearXRotateTranslateB2DHomMatrix(fShearX
, fRotate
, aTranslate
)
135 const GraphicObject
& rGraphicObject
= GetGrafObject().GetGraphicObject();
136 const GraphicAttr aLocalGrafInfo
;
137 const drawinglayer::primitive2d::Primitive2DReference
xReferenceB(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
139 drawinglayer::attribute::SdrLineFillShadowTextAttribute(),
143 xRetval
.push_back(xReferenceB
);
149 drawinglayer::primitive2d::Primitive2DContainer
ViewContactOfGraphic::createVIP2DSForDraft(
150 const basegfx::B2DHomMatrix
& rObjectMatrix
,
151 const drawinglayer::attribute::SdrLineFillShadowTextAttribute
& rAttribute
) const
153 drawinglayer::primitive2d::Primitive2DContainer xRetval
;
154 GraphicObject aEmptyGraphicObject
;
155 GraphicAttr aEmptyGraphicAttr
;
157 // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts
158 const drawinglayer::primitive2d::Primitive2DReference
xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
163 xRetval
= drawinglayer::primitive2d::Primitive2DContainer
{ xReferenceA
};
165 if(rAttribute
.getLine().isDefault())
167 // create a surrounding frame when no linestyle given
168 const Color
aColor(Application::GetSettings().GetStyleSettings().GetShadowColor());
169 const basegfx::BColor
aBColor(aColor
.getBColor());
170 basegfx::B2DPolygon
aOutline(basegfx::tools::createUnitPolygon());
171 aOutline
.transform(rObjectMatrix
);
174 drawinglayer::primitive2d::Primitive2DReference(
175 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
180 // decompose object matrix to get single values
181 basegfx::B2DVector aScale
, aTranslate
;
182 double fRotate
, fShearX
;
183 rObjectMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
185 // define a distance value, used for distance from bitmap to borders and from bitmap
186 // to text, too (2 mm)
187 const double fDistance(200.0);
189 // consume borders from values
190 aScale
.setX(std::max(0.0, aScale
.getX() - (2.0 * fDistance
)));
191 aScale
.setY(std::max(0.0, aScale
.getY() - (2.0 * fDistance
)));
192 aTranslate
.setX(aTranslate
.getX() + fDistance
);
193 aTranslate
.setY(aTranslate
.getY() + fDistance
);
195 // draw a draft bitmap
196 const BitmapEx
aDraftBitmap(BMAP_GrafikEi
);
198 if(!aDraftBitmap
.IsEmpty())
200 Size
aPrefSize(aDraftBitmap
.GetPrefSize());
202 if(MapUnit::MapPixel
== aDraftBitmap
.GetPrefMapMode().GetMapUnit())
204 aPrefSize
= Application::GetDefaultDevice()->PixelToLogic(aDraftBitmap
.GetSizePixel(), MapUnit::Map100thMM
);
208 aPrefSize
= OutputDevice::LogicToLogic(aPrefSize
, aDraftBitmap
.GetPrefMapMode(), MapUnit::Map100thMM
);
211 const double fBitmapScaling(2.0);
212 const double fWidth(aPrefSize
.getWidth() * fBitmapScaling
);
213 const double fHeight(aPrefSize
.getHeight() * fBitmapScaling
);
215 if(basegfx::fTools::more(fWidth
, 1.0)
216 && basegfx::fTools::more(fHeight
, 1.0)
217 && basegfx::fTools::lessOrEqual(fWidth
, aScale
.getX())
218 && basegfx::fTools::lessOrEqual(fHeight
, aScale
.getY()))
220 const basegfx::B2DHomMatrix
aBitmapMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
221 fWidth
, fHeight
, fShearX
, fRotate
, aTranslate
.getX(), aTranslate
.getY()));
224 drawinglayer::primitive2d::Primitive2DReference(
225 new drawinglayer::primitive2d::BitmapPrimitive2D(
226 BitmapEx(aDraftBitmap
),
229 // consume bitmap size in X
230 aScale
.setX(std::max(0.0, aScale
.getX() - (fWidth
+ fDistance
)));
231 aTranslate
.setX(aTranslate
.getX() + fWidth
+ fDistance
);
235 // Build the text for the draft object
236 OUString aDraftText
= GetGrafObject().GetFileName();
238 if (aDraftText
.isEmpty())
240 aDraftText
= GetGrafObject().GetName();
241 aDraftText
+= " ...";
244 if (!aDraftText
.isEmpty() && GetGrafObject().GetModel())
246 // #i103255# Goal is to produce TextPrimitives which hold the given text as
247 // BlockText in the available space. It would be very tricky to do
248 // an own word wrap/line layout here.
249 // Using SdrBlockTextPrimitive2D OTOH is critical since it internally
250 // uses the SdrObject it references. To solve this, create a temp
251 // SdrObject with Attributes and Text, generate a SdrBlockTextPrimitive2D
252 // directly and immediately decompose it. After that, it is no longer
253 // needed and can be deleted.
255 // create temp RectObj as TextObj and set needed attributes
256 SdrRectObj
aRectObj(OBJ_TEXT
);
257 aRectObj
.SetModel(GetGrafObject().GetModel());
258 aRectObj
.NbcSetText(aDraftText
);
259 aRectObj
.SetMergedItem(SvxColorItem(Color(COL_LIGHTRED
), EE_CHAR_COLOR
));
261 // get SdrText and OPO
262 SdrText
* pSdrText
= aRectObj
.getText(0);
263 OutlinerParaObject
* pOPO
= aRectObj
.GetOutlinerParaObject();
267 // directly use the remaining space as TextRangeTransform
268 const basegfx::B2DHomMatrix
aTextRangeTransform(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
269 aScale
, fShearX
, fRotate
, aTranslate
));
271 // directly create temp SdrBlockTextPrimitive2D
272 rtl::Reference
< drawinglayer::primitive2d::SdrBlockTextPrimitive2D
> xBlockTextPrimitive(new drawinglayer::primitive2d::SdrBlockTextPrimitive2D(
276 SDRTEXTHORZADJUST_LEFT
,
277 SDRTEXTVERTADJUST_TOP
,
284 // decompose immediately with neutral ViewInformation. This will
285 // layout the text to more simple TextPrimitives from drawinglayer
286 const drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
287 xBlockTextPrimitive
->get2DDecomposition(xRetval
, aViewInformation2D
);
294 drawinglayer::primitive2d::Primitive2DContainer
ViewContactOfGraphic::createViewIndependentPrimitive2DSequence() const
296 drawinglayer::primitive2d::Primitive2DContainer xRetval
;
297 const SfxItemSet
& rItemSet
= GetGrafObject().GetMergedItemSet();
299 // create and fill GraphicAttr
300 GraphicAttr aLocalGrafInfo
;
301 const sal_uInt16
nTrans(static_cast<const SdrGrafTransparenceItem
&>(rItemSet
.Get(SDRATTR_GRAFTRANSPARENCE
)).GetValue());
302 const SdrGrafCropItem
& rCrop(static_cast<const SdrGrafCropItem
&>(rItemSet
.Get(SDRATTR_GRAFCROP
)));
303 aLocalGrafInfo
.SetLuminance(static_cast<const SdrGrafLuminanceItem
&>(rItemSet
.Get(SDRATTR_GRAFLUMINANCE
)).GetValue());
304 aLocalGrafInfo
.SetContrast(static_cast<const SdrGrafContrastItem
&>(rItemSet
.Get(SDRATTR_GRAFCONTRAST
)).GetValue());
305 aLocalGrafInfo
.SetChannelR(static_cast<const SdrGrafRedItem
&>(rItemSet
.Get(SDRATTR_GRAFRED
)).GetValue());
306 aLocalGrafInfo
.SetChannelG(static_cast<const SdrGrafGreenItem
&>(rItemSet
.Get(SDRATTR_GRAFGREEN
)).GetValue());
307 aLocalGrafInfo
.SetChannelB(static_cast<const SdrGrafBlueItem
&>(rItemSet
.Get(SDRATTR_GRAFBLUE
)).GetValue());
308 aLocalGrafInfo
.SetGamma(static_cast<const SdrGrafGamma100Item
&>(rItemSet
.Get(SDRATTR_GRAFGAMMA
)).GetValue() * 0.01);
309 aLocalGrafInfo
.SetTransparency((sal_uInt8
)::basegfx::fround(std::min(nTrans
, (sal_uInt16
)100) * 2.55));
310 aLocalGrafInfo
.SetInvert(static_cast<const SdrGrafInvertItem
&>(rItemSet
.Get(SDRATTR_GRAFINVERT
)).GetValue());
311 aLocalGrafInfo
.SetDrawMode(static_cast<const SdrGrafModeItem
&>(rItemSet
.Get(SDRATTR_GRAFMODE
)).GetValue());
312 aLocalGrafInfo
.SetCrop(rCrop
.GetLeft(), rCrop
.GetTop(), rCrop
.GetRight(), rCrop
.GetBottom());
314 // we have content if graphic is not completely transparent
315 const bool bHasContent(255L != aLocalGrafInfo
.GetTransparency());
316 drawinglayer::attribute::SdrLineFillShadowTextAttribute
aAttribute(
317 drawinglayer::primitive2d::createNewSdrLineFillShadowTextAttribute(
319 GetGrafObject().getText(0),
322 // take unrotated snap rect for position and size. Directly use model data, not getBoundRect() or getSnapRect()
323 // which will use the primitive data we just create in the near future
324 tools::Rectangle rRectangle
= GetGrafObject().GetGeoRect();
325 // Hack for calc, transform position of object according
326 // to current zoom so as objects relative position to grid
328 rRectangle
+= GetGrafObject().GetGridOffset();
329 const ::basegfx::B2DRange
aObjectRange(
330 rRectangle
.Left(), rRectangle
.Top(),
331 rRectangle
.Right(), rRectangle
.Bottom());
333 // look for mirroring
334 const GeoStat
& rGeoStat(GetGrafObject().GetGeoStat());
335 const sal_Int32
nRotationAngle(rGeoStat
.nRotationAngle
);
336 const bool bRota180(18000 == nRotationAngle
);
337 const bool bMirrored(GetGrafObject().IsMirrored());
338 const sal_uInt16
nMirrorCase(bRota180
? (bMirrored
? 3 : 4) : (bMirrored
? 2 : 1));
339 bool bHMirr((2 == nMirrorCase
) || (4 == nMirrorCase
));
340 bool bVMirr((3 == nMirrorCase
) || (4 == nMirrorCase
));
342 // set mirror flags at LocalGrafInfo. Take into account that the geometry in
343 // aObjectRange is already changed and rotated when bRota180 is used. To rebuild
344 // that old behaviour (as long as part of the model data), correct the H/V flags
345 // accordingly. The created bitmapPrimitive WILL use the rotation, too.
348 // if bRota180 which is used for vertical mirroring, the graphic will already be rotated
349 // by 180 degrees. To correct, switch off VMirror and invert HMirroring.
356 aLocalGrafInfo
.SetMirrorFlags((bHMirr
? BmpMirrorFlags::Horizontal
: BmpMirrorFlags::NONE
)|(bVMirr
? BmpMirrorFlags::Vertical
: BmpMirrorFlags::NONE
));
359 // fill object matrix
360 const double fShearX(rGeoStat
.nShearAngle
? tan((36000 - rGeoStat
.nShearAngle
) * F_PI18000
) : 0.0);
361 const double fRotate(nRotationAngle
? (36000 - nRotationAngle
) * F_PI18000
: 0.0);
362 const basegfx::B2DHomMatrix
aObjectMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
363 aObjectRange
.getWidth(), aObjectRange
.getHeight(),
365 aObjectRange
.getMinX(), aObjectRange
.getMinY()));
367 // get the current, unchanged graphic object from SdrGrafObj
368 const GraphicObject
& rGraphicObject
= GetGrafObject().GetGraphicObject();
370 if(visualisationUsesPresObj())
372 // it's an EmptyPresObj, create the SdrGrafPrimitive2D without content and another scaled one
373 // with the content which is the placeholder graphic
374 xRetval
= createVIP2DSForPresObj(aObjectMatrix
, aAttribute
);
376 #ifndef IOS // Enforce swap-in for tiled rendering for now, while we have no delayed updating mechanism
377 else if(visualisationUsesDraft())
379 // #i102380# The graphic is swapped out. To not force a swap-in here, there is a mechanism
380 // which shows a swapped-out-visualisation (which gets created here now) and an asynchronious
381 // visual update mechanism for swapped-out graphics when they were loaded (see AsynchGraphicLoadingEvent
382 // and ViewObjectContactOfGraphic implementation). Not forcing the swap-in here allows faster
383 // (non-blocking) processing here and thus in the effect e.g. fast scrolling through pages
384 xRetval
= createVIP2DSForDraft(aObjectMatrix
, aAttribute
);
389 // create primitive. Info: Calling the copy-constructor of GraphicObject in this
390 // SdrGrafPrimitive2D constructor will force a full swap-in of the graphic
391 const drawinglayer::primitive2d::Primitive2DReference
xReference(
392 new drawinglayer::primitive2d::SdrGrafPrimitive2D(
398 xRetval
= drawinglayer::primitive2d::Primitive2DContainer
{ xReference
};
401 // always append an invisible outline for the cases where no visible content exists
403 drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
409 bool ViewContactOfGraphic::visualisationUsesPresObj() const
411 return GetGrafObject().IsEmptyPresObj();
414 bool ViewContactOfGraphic::visualisationUsesDraft() const
416 // no draft when already PresObj
417 if(visualisationUsesPresObj())
420 // draft when swapped out
421 const GraphicObject
& rGraphicObject
= GetGrafObject().GetGraphicObject();
422 static bool bAllowReplacements(true);
424 if(rGraphicObject
.IsSwappedOut() && bAllowReplacements
)
427 // draft when no graphic
428 if(GraphicType::NONE
== rGraphicObject
.GetType() || GraphicType::Default
== rGraphicObject
.GetType())
434 } // end of namespace contact
435 } // end of namespace sdr
437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */