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 <sdgtritm.hxx>
24 #include <svx/sdgluitm.hxx>
25 #include <sdgcoitm.hxx>
26 #include <svx/sdggaitm.hxx>
27 #include <sdginitm.hxx>
28 #include <svx/sdgmoitm.hxx>
29 #include <sdr/primitive2d/sdrattributecreator.hxx>
30 #include <svl/itemset.hxx>
31 #include <tools/debug.hxx>
33 #include <svx/sdgcpitm.hxx>
34 #include <svx/sdr/contact/viewobjectcontact.hxx>
35 #include <svx/sdr/contact/objectcontact.hxx>
36 #include <basegfx/matrix/b2dhommatrix.hxx>
37 #include <sdr/primitive2d/sdrgrafprimitive2d.hxx>
38 #include <vcl/canvastools.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/settings.hxx>
41 #include <basegfx/polygon/b2dpolygontools.hxx>
42 #include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
43 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
44 #include <sdr/primitive2d/sdrtextprimitive2d.hxx>
45 #include <editeng/eeitem.hxx>
46 #include <editeng/colritem.hxx>
47 #include <basegfx/matrix/b2dhommatrixtools.hxx>
48 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
49 #include <drawinglayer/primitive2d/exclusiveeditviewprimitive2d.hxx>
51 #include <bitmaps.hlst>
53 namespace sdr::contact
55 // Create an 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 drawinglayer::primitive2d::Primitive2DContainer
ViewContactOfGraphic::createVIP2DSForPresObj(
75 const basegfx::B2DHomMatrix
& rObjectMatrix
,
76 const drawinglayer::attribute::SdrLineFillEffectsTextAttribute
& rAttribute
) const
78 drawinglayer::primitive2d::Primitive2DContainer xRetval
;
79 GraphicObject aEmptyGraphicObject
;
80 GraphicAttr aEmptyGraphicAttr
;
82 // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts
83 const drawinglayer::primitive2d::Primitive2DReference
xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
89 xRetval
= drawinglayer::primitive2d::Primitive2DContainer
{ xReferenceA
};
91 // SdrGrafPrimitive2D with content (which is the preview graphic) scaled to smaller size and
93 basegfx::B2DHomMatrix aSmallerMatrix
;
95 // #i94431# for some reason, i forgot to take the PrefMapMode of the graphic
96 // into account. Since EmptyPresObj's are only used in Draw/Impress, it is
97 // safe to assume 100th mm as target.
98 Size
aPrefSize(GetGrafObject().GetGrafPrefSize());
100 if(MapUnit::MapPixel
== GetGrafObject().GetGrafPrefMapMode().GetMapUnit())
102 aPrefSize
= Application::GetDefaultDevice()->PixelToLogic(aPrefSize
, MapMode(MapUnit::Map100thMM
));
106 aPrefSize
= OutputDevice::LogicToLogic(aPrefSize
, GetGrafObject().GetGrafPrefMapMode(), MapMode(MapUnit::Map100thMM
));
109 // decompose object matrix to get single values
110 basegfx::B2DVector aScale
, aTranslate
;
111 double fRotate
, fShearX
;
112 rObjectMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
114 const double fOffsetX((aScale
.getX() - aPrefSize
.getWidth()) / 2.0);
115 const double fOffsetY((aScale
.getY() - aPrefSize
.getHeight()) / 2.0);
117 if (fOffsetX
>= 0.0 && fOffsetY
>= 0.0)
119 // create the EmptyPresObj fallback visualisation. The fallback graphic
120 // is already provided in rGraphicObject in this case, use it
121 aSmallerMatrix
= basegfx::utils::createScaleTranslateB2DHomMatrix(aPrefSize
.getWidth(), aPrefSize
.getHeight(), fOffsetX
, fOffsetY
);
122 aSmallerMatrix
= basegfx::utils::createShearXRotateTranslateB2DHomMatrix(fShearX
, fRotate
, aTranslate
)
125 const GraphicObject
& rGraphicObject
= GetGrafObject().GetGraphicObject();
126 const GraphicAttr aLocalGrafInfo
;
127 const drawinglayer::primitive2d::Primitive2DReference
xReferenceB(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
129 drawinglayer::attribute::SdrLineFillEffectsTextAttribute(),
133 // embed it to a ExclusiveEditViewPrimitive2D to allow to decide in
134 // the primitive if to visualize or not
135 const drawinglayer::primitive2d::Primitive2DReference
aEmbedded(
136 new drawinglayer::primitive2d::ExclusiveEditViewPrimitive2D(
137 drawinglayer::primitive2d::Primitive2DContainer
{ xReferenceB
} ));
139 xRetval
.push_back(aEmbedded
);
145 drawinglayer::primitive2d::Primitive2DContainer
ViewContactOfGraphic::createVIP2DSForDraft(
146 const basegfx::B2DHomMatrix
& rObjectMatrix
,
147 const drawinglayer::attribute::SdrLineFillEffectsTextAttribute
& rAttribute
) const
149 drawinglayer::primitive2d::Primitive2DContainer xRetval
;
150 GraphicObject aEmptyGraphicObject
;
151 GraphicAttr aEmptyGraphicAttr
;
153 // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts
154 const drawinglayer::primitive2d::Primitive2DReference
xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
159 xRetval
= drawinglayer::primitive2d::Primitive2DContainer
{ xReferenceA
};
161 if(rAttribute
.getLine().isDefault())
163 // create a surrounding frame when no linestyle given
164 const Color
aColor(Application::GetSettings().GetStyleSettings().GetShadowColor());
165 const basegfx::BColor
aBColor(aColor
.getBColor());
166 basegfx::B2DPolygon
aOutline(basegfx::utils::createUnitPolygon());
167 aOutline
.transform(rObjectMatrix
);
170 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
175 // decompose object matrix to get single values
176 basegfx::B2DVector aScale
, aTranslate
;
177 double fRotate
, fShearX
;
178 rObjectMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
180 // define a distance value, used for distance from bitmap to borders and from bitmap
181 // to text, too (2 mm)
182 const double fDistance(200.0);
184 // consume borders from values
185 aScale
.setX(std::max(0.0, aScale
.getX() - (2.0 * fDistance
)));
186 aScale
.setY(std::max(0.0, aScale
.getY() - (2.0 * fDistance
)));
187 aTranslate
.setX(aTranslate
.getX() + fDistance
);
188 aTranslate
.setY(aTranslate
.getY() + fDistance
);
190 // draw a draft bitmap
191 const BitmapEx
aDraftBitmap(BMAP_GrafikEi
);
193 if(!aDraftBitmap
.IsEmpty())
195 Size
aPrefSize(aDraftBitmap
.GetPrefSize());
197 if(MapUnit::MapPixel
== aDraftBitmap
.GetPrefMapMode().GetMapUnit())
199 aPrefSize
= Application::GetDefaultDevice()->PixelToLogic(aDraftBitmap
.GetSizePixel(), MapMode(MapUnit::Map100thMM
));
203 aPrefSize
= OutputDevice::LogicToLogic(aPrefSize
, aDraftBitmap
.GetPrefMapMode(), MapMode(MapUnit::Map100thMM
));
206 const double fBitmapScaling(2.0);
207 const double fWidth(aPrefSize
.getWidth() * fBitmapScaling
);
208 const double fHeight(aPrefSize
.getHeight() * fBitmapScaling
);
210 if(basegfx::fTools::more(fWidth
, 1.0)
211 && basegfx::fTools::more(fHeight
, 1.0)
212 && basegfx::fTools::lessOrEqual(fWidth
, aScale
.getX())
213 && basegfx::fTools::lessOrEqual(fHeight
, aScale
.getY()))
215 const basegfx::B2DHomMatrix
aBitmapMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
216 fWidth
, fHeight
, fShearX
, fRotate
, aTranslate
.getX(), aTranslate
.getY()));
219 new drawinglayer::primitive2d::BitmapPrimitive2D(
223 // consume bitmap size in X
224 aScale
.setX(std::max(0.0, aScale
.getX() - (fWidth
+ fDistance
)));
225 aTranslate
.setX(aTranslate
.getX() + fWidth
+ fDistance
);
229 // Build the text for the draft object
230 OUString aDraftText
= GetGrafObject().GetFileName();
232 if (aDraftText
.isEmpty())
234 aDraftText
= GetGrafObject().GetName() + " ...";
237 if (!aDraftText
.isEmpty())
239 // #i103255# Goal is to produce TextPrimitives which hold the given text as
240 // BlockText in the available space. It would be very tricky to do
241 // an own word wrap/line layout here.
242 // Using SdrBlockTextPrimitive2D OTOH is critical since it internally
243 // uses the SdrObject it references. To solve this, create a temp
244 // SdrObject with Attributes and Text, generate a SdrBlockTextPrimitive2D
245 // directly and immediately decompose it. After that, it is no longer
246 // needed and can be deleted.
248 // create temp RectObj as TextObj and set needed attributes
249 rtl::Reference
<SdrRectObj
> pRectObj(new SdrRectObj(GetGrafObject().getSdrModelFromSdrObject(), SdrObjKind::Text
));
250 pRectObj
->NbcSetText(aDraftText
);
251 pRectObj
->SetMergedItem(SvxColorItem(COL_LIGHTRED
, EE_CHAR_COLOR
));
253 // get SdrText and OPO
254 SdrText
* pSdrText(pRectObj
->getText(0));
255 OutlinerParaObject
* pOPO(pRectObj
->GetOutlinerParaObject());
259 // directly use the remaining space as TextRangeTransform
260 const basegfx::B2DHomMatrix
aTextRangeTransform(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
261 aScale
, fShearX
, fRotate
, aTranslate
));
263 // directly create temp SdrBlockTextPrimitive2D
264 rtl::Reference
< drawinglayer::primitive2d::SdrBlockTextPrimitive2D
> xBlockTextPrimitive(new drawinglayer::primitive2d::SdrBlockTextPrimitive2D(
268 SDRTEXTHORZADJUST_LEFT
,
269 SDRTEXTVERTADJUST_TOP
,
275 // decompose immediately with neutral ViewInformation. This will
276 // layout the text to more simple TextPrimitives from drawinglayer
277 const drawinglayer::geometry::ViewInformation2D aViewInformation2D
;
278 xBlockTextPrimitive
->get2DDecomposition(xRetval
, aViewInformation2D
);
285 void ViewContactOfGraphic::createViewIndependentPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
) const
287 const SfxItemSet
& rItemSet
= GetGrafObject().GetMergedItemSet();
289 // create and fill GraphicAttr
290 GraphicAttr aLocalGrafInfo
;
291 const sal_uInt16
nTrans(rItemSet
.Get(SDRATTR_GRAFTRANSPARENCE
).GetValue());
292 const SdrGrafCropItem
& rCrop(rItemSet
.Get(SDRATTR_GRAFCROP
));
293 aLocalGrafInfo
.SetLuminance(rItemSet
.Get(SDRATTR_GRAFLUMINANCE
).GetValue());
294 aLocalGrafInfo
.SetContrast(rItemSet
.Get(SDRATTR_GRAFCONTRAST
).GetValue());
295 aLocalGrafInfo
.SetChannelR(rItemSet
.Get(SDRATTR_GRAFRED
).GetValue());
296 aLocalGrafInfo
.SetChannelG(rItemSet
.Get(SDRATTR_GRAFGREEN
).GetValue());
297 aLocalGrafInfo
.SetChannelB(rItemSet
.Get(SDRATTR_GRAFBLUE
).GetValue());
298 aLocalGrafInfo
.SetGamma(rItemSet
.Get(SDRATTR_GRAFGAMMA
).GetValue() * 0.01);
299 aLocalGrafInfo
.SetAlpha(255 - static_cast<sal_uInt8
>(::basegfx::fround(std::min(nTrans
, sal_uInt16(100)) * 2.55)));
300 aLocalGrafInfo
.SetInvert(rItemSet
.Get(SDRATTR_GRAFINVERT
).GetValue());
301 aLocalGrafInfo
.SetDrawMode(rItemSet
.Get(SDRATTR_GRAFMODE
).GetValue());
302 aLocalGrafInfo
.SetCrop(rCrop
.GetLeft(), rCrop
.GetTop(), rCrop
.GetRight(), rCrop
.GetBottom());
304 // we have content if graphic is not completely transparent
305 const bool bHasContent(0 != aLocalGrafInfo
.GetAlpha());
306 drawinglayer::attribute::SdrLineFillEffectsTextAttribute
aAttribute(
307 drawinglayer::primitive2d::createNewSdrLineFillEffectsTextAttribute(
309 GetGrafObject().getText(0),
312 // take unrotated snap rect for position and size. Directly use model data, not getBoundRect() or getSnapRect()
313 // which will use the primitive data we just create in the near future
314 const ::basegfx::B2DRange aObjectRange
= vcl::unotools::b2DRectangleFromRectangle(GetGrafObject().GetGeoRect());
316 // look for mirroring
317 const GeoStat
& rGeoStat(GetGrafObject().GetGeoStat());
318 const Degree100
nRotationAngle(rGeoStat
.m_nRotationAngle
);
319 const bool bMirrored(GetGrafObject().IsMirrored());
322 aLocalGrafInfo
.SetMirrorFlags(BmpMirrorFlags::Horizontal
);
324 // fill object matrix
325 const double fShearX(-rGeoStat
.mfTanShearAngle
);
326 const double fRotate(nRotationAngle
? toRadians(36000_deg100
- nRotationAngle
) : 0.0);
327 const basegfx::B2DHomMatrix
aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
328 aObjectRange
.getWidth(), aObjectRange
.getHeight(),
330 aObjectRange
.getMinX(), aObjectRange
.getMinY()));
332 // get the current, unchanged graphic object from SdrGrafObj
333 const GraphicObject
& rGraphicObject
= GetGrafObject().GetGraphicObject();
335 if(visualisationUsesPresObj())
337 // it's an EmptyPresObj, create the SdrGrafPrimitive2D without content and another scaled one
338 // with the content which is the placeholder graphic
339 rVisitor
.visit(createVIP2DSForPresObj(aObjectMatrix
, aAttribute
));
341 #ifndef IOS // Enforce swap-in for tiled rendering for now, while we have no delayed updating mechanism
342 else if(visualisationUsesDraft())
344 // #i102380# The graphic is swapped out. To not force a swap-in here, there is a mechanism
345 // which shows a swapped-out-visualisation (which gets created here now) and an asynchronous
346 // visual update mechanism for swapped-out graphics when they were loaded (see AsynchGraphicLoadingEvent
347 // and ViewObjectContactOfGraphic implementation). Not forcing the swap-in here allows faster
348 // (non-blocking) processing here and thus in the effect e.g. fast scrolling through pages
349 rVisitor
.visit(createVIP2DSForDraft(aObjectMatrix
, aAttribute
));
354 // create primitive. Info: Calling the copy-constructor of GraphicObject in this
355 // SdrGrafPrimitive2D constructor will force a full swap-in of the graphic
356 const drawinglayer::primitive2d::Primitive2DReference
xReference(
357 new drawinglayer::primitive2d::SdrGrafPrimitive2D(
363 rVisitor
.visit(xReference
);
366 // always append an invisible outline for the cases where no visible content exists
368 drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
372 bool ViewContactOfGraphic::visualisationUsesPresObj() const
374 return GetGrafObject().IsEmptyPresObj();
377 bool ViewContactOfGraphic::visualisationUsesDraft() const
379 // no draft when already PresObj
380 if(visualisationUsesPresObj())
383 // draft when swapped out
384 const GraphicObject
& rGraphicObject
= GetGrafObject().GetGraphicObject();
386 // draft when no graphic
387 return GraphicType::NONE
== rGraphicObject
.GetType() || GraphicType::Default
== rGraphicObject
.GetType();
390 } // end of namespace
392 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */