1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: viewcontactofgraphic.cxx,v $
10 * $Revision: 1.14.18.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include <svx/sdr/contact/viewcontactofgraphic.hxx>
34 #include <svx/sdr/contact/viewobjectcontactofgraphic.hxx>
35 #include <svx/svdograf.hxx>
36 #include <svx/sdr/attribute/sdrallattribute.hxx>
37 #include <svx/sdr/primitive2d/sdrattributecreator.hxx>
38 #include <svtools/itemset.hxx>
40 #ifndef ITEMID_GRF_CROP
41 #define ITEMID_GRF_CROP 0
44 #include <svx/sdgcpitm.hxx>
45 #include <drawinglayer/attribute/sdrattribute.hxx>
46 #include <svx/sdr/contact/displayinfo.hxx>
47 #include <svx/sdr/contact/viewobjectcontact.hxx>
48 #include <svx/sdr/contact/objectcontact.hxx>
49 #include <svx/sdr/event/eventhandler.hxx>
50 #include <basegfx/matrix/b2dhommatrix.hxx>
51 #include <svx/sdr/primitive2d/sdrgrafprimitive2d.hxx>
53 #include <svdglob.hxx>
54 #include <vcl/svapp.hxx>
56 #include <basegfx/polygon/b2dpolygontools.hxx>
57 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
58 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
59 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
60 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
61 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
63 #include <svx/sdr/primitive2d/sdrtextprimitive2d.hxx>
64 #include <svx/eeitem.hxx>
65 #include <svx/colritem.hxx>
66 //#include <svx/xtable.hxx>
68 //////////////////////////////////////////////////////////////////////////////
74 // Create a Object-Specific ViewObjectContact, set ViewContact and
75 // ObjectContact. Always needs to return something.
76 ViewObjectContact
& ViewContactOfGraphic::CreateObjectSpecificViewObjectContact(ObjectContact
& rObjectContact
)
78 ViewObjectContact
* pRetval
= new ViewObjectContactOfGraphic(rObjectContact
, *this);
79 DBG_ASSERT(pRetval
, "ViewContact::CreateObjectSpecificViewObjectContact() failed (!)");
84 ViewContactOfGraphic::ViewContactOfGraphic(SdrGrafObj
& rGrafObj
)
85 : ViewContactOfTextObj(rGrafObj
)
89 ViewContactOfGraphic::~ViewContactOfGraphic()
93 void ViewContactOfGraphic::flushGraphicObjects()
95 // #i102380# The graphic is swapped out. To let that have an effect ist is necessary to
96 // delete copies of the GraphicObject which are not swapped out and have no SwapHandler set
97 // (this is what happnes when the GraphicObject gets copied to a SdrGrafPrimitive2D). This
98 // is best achieved for the VC by clearing the local decomposition cache. It would be possible
99 // to also do this for the VOC cache, but that VOCs exist exactly expresss that the object
100 // gets visualised, so this would be wrong.
101 flushViewIndependentPrimitive2DSequence();
104 drawinglayer::primitive2d::Primitive2DSequence
ViewContactOfGraphic::createVIP2DSForPresObj(
105 const basegfx::B2DHomMatrix
& rObjectMatrix
,
106 const drawinglayer::attribute::SdrLineFillShadowTextAttribute
& rAttribute
,
107 const GraphicAttr
& rLocalGrafInfo
) const
109 drawinglayer::primitive2d::Primitive2DSequence xRetval
;
110 GraphicObject aEmptyGraphicObject
;
111 GraphicAttr aEmptyGraphicAttr
;
113 // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts
114 const drawinglayer::primitive2d::Primitive2DReference
xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
119 xRetval
= drawinglayer::primitive2d::Primitive2DSequence(&xReferenceA
, 1);
121 // SdrGrafPrimitive2D with content (which is the preview graphic) scaled to smaller size and
122 // without attributes
123 basegfx::B2DHomMatrix aSmallerMatrix
;
125 // #i94431# for some reason, i forgot to take the PrefMapMode of the graphic
126 // into account. Since EmptyPresObj's are only used in Draw/Impress, it is
127 // safe to assume 100th mm as target.
128 Size
aPrefSize(GetGrafObject().GetGrafPrefSize());
130 if(MAP_PIXEL
== GetGrafObject().GetGrafPrefMapMode().GetMapUnit())
132 aPrefSize
= Application::GetDefaultDevice()->PixelToLogic(aPrefSize
, MAP_100TH_MM
);
136 aPrefSize
= Application::GetDefaultDevice()->LogicToLogic(aPrefSize
, GetGrafObject().GetGrafPrefMapMode(), MAP_100TH_MM
);
139 // decompose object matrix to get single values
140 basegfx::B2DVector aScale
, aTranslate
;
141 double fRotate
, fShearX
;
142 rObjectMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
144 const double fOffsetX((aScale
.getX() - aPrefSize
.getWidth()) / 2.0);
145 const double fOffsetY((aScale
.getY() - aPrefSize
.getHeight()) / 2.0);
147 if(basegfx::fTools::moreOrEqual(fOffsetX
, 0.0) && basegfx::fTools::moreOrEqual(fOffsetY
, 0.0))
149 // create the EmptyPresObj fallback visualisation. The fallback graphic
150 // is already provided in rGraphicObject in this case, use it
151 aSmallerMatrix
.scale(aPrefSize
.getWidth(), aPrefSize
.getHeight());
152 aSmallerMatrix
.translate(fOffsetX
, fOffsetY
);
153 aSmallerMatrix
.shearX(fShearX
);
154 aSmallerMatrix
.rotate(fRotate
);
155 aSmallerMatrix
.translate(aTranslate
.getX(), aTranslate
.getY());
157 const GraphicObject
& rGraphicObject
= GetGrafObject().GetGraphicObject(false);
158 const drawinglayer::attribute::SdrLineFillShadowTextAttribute
aEmptyAttributes(0, 0, 0, 0, 0, 0);
159 const drawinglayer::primitive2d::Primitive2DReference
xReferenceB(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
165 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval
, xReferenceB
);
171 drawinglayer::primitive2d::Primitive2DSequence
ViewContactOfGraphic::createVIP2DSForDraft(
172 const basegfx::B2DHomMatrix
& rObjectMatrix
,
173 const drawinglayer::attribute::SdrLineFillShadowTextAttribute
& rAttribute
) const
175 drawinglayer::primitive2d::Primitive2DSequence xRetval
;
176 GraphicObject aEmptyGraphicObject
;
177 GraphicAttr aEmptyGraphicAttr
;
179 // SdrGrafPrimitive2D without content in original size which carries all eventual attributes and texts
180 const drawinglayer::primitive2d::Primitive2DReference
xReferenceA(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
185 xRetval
= drawinglayer::primitive2d::Primitive2DSequence(&xReferenceA
, 1);
187 if(!rAttribute
.getLine())
189 // create a surrounding frame when no linestyle given
190 const Color
aColor(Application::GetSettings().GetStyleSettings().GetShadowColor());
191 const basegfx::BColor
aBColor(aColor
.getBColor());
192 const basegfx::B2DRange
aUnitRange(0.0, 0.0, 1.0, 1.0);
194 basegfx::B2DPolygon
aOutline(basegfx::tools::createPolygonFromRect(aUnitRange
));
195 aOutline
.transform(rObjectMatrix
);
197 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval
,
198 drawinglayer::primitive2d::Primitive2DReference(
199 new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
204 // decompose object matrix to get single values
205 basegfx::B2DVector aScale
, aTranslate
;
206 double fRotate
, fShearX
;
207 rObjectMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
209 // define a distance value, used for distance from bitmap to borders and from bitmap
210 // to text, too (2 mm)
211 const double fDistance(200.0);
213 // consume borders from values
214 aScale
.setX(std::max(0.0, aScale
.getX() - (2.0 * fDistance
)));
215 aScale
.setY(std::max(0.0, aScale
.getY() - (2.0 * fDistance
)));
216 aTranslate
.setX(aTranslate
.getX() + fDistance
);
217 aTranslate
.setY(aTranslate
.getY() + fDistance
);
219 // draw a draft bitmap
220 const Bitmap
aDraftBitmap(ResId(BMAP_GrafikEi
, *ImpGetResMgr()));
222 if(!aDraftBitmap
.IsEmpty())
224 Size
aPrefSize(aDraftBitmap
.GetPrefSize());
226 if(MAP_PIXEL
== aDraftBitmap
.GetPrefMapMode().GetMapUnit())
228 aPrefSize
= Application::GetDefaultDevice()->PixelToLogic(aDraftBitmap
.GetSizePixel(), MAP_100TH_MM
);
232 aPrefSize
= Application::GetDefaultDevice()->LogicToLogic(aPrefSize
, aDraftBitmap
.GetPrefMapMode(), MAP_100TH_MM
);
235 const double fBitmapScaling(2.0);
236 const double fWidth(aPrefSize
.getWidth() * fBitmapScaling
);
237 const double fHeight(aPrefSize
.getHeight() * fBitmapScaling
);
239 if(basegfx::fTools::more(fWidth
, 1.0)
240 && basegfx::fTools::more(fHeight
, 1.0)
241 && basegfx::fTools::lessOrEqual(fWidth
, aScale
.getX())
242 && basegfx::fTools::lessOrEqual(fHeight
, aScale
.getY()))
244 basegfx::B2DHomMatrix aBitmapMatrix
;
246 aBitmapMatrix
.scale(fWidth
, fHeight
);
247 aBitmapMatrix
.shearX(fShearX
);
248 aBitmapMatrix
.rotate(fRotate
);
249 aBitmapMatrix
.translate(aTranslate
.getX(), aTranslate
.getY());
251 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval
,
252 drawinglayer::primitive2d::Primitive2DReference(
253 new drawinglayer::primitive2d::BitmapPrimitive2D(
254 BitmapEx(aDraftBitmap
),
257 // consume bitmap size in X
258 aScale
.setX(std::max(0.0, aScale
.getX() - (fWidth
+ fDistance
)));
259 aTranslate
.setX(aTranslate
.getX() + fWidth
+ fDistance
);
263 // Build the text for the draft object
264 XubString aDraftText
= GetGrafObject().GetFileName();
266 if(!aDraftText
.Len())
268 aDraftText
= GetGrafObject().GetName();
269 aDraftText
.AppendAscii(" ...");
272 if(aDraftText
.Len() && GetGrafObject().GetModel())
274 // #i103255# Goal is to produce TextPrimitives which hold the given text as
275 // BlockText in the available space. It would be very tricky to do
276 // an own word wrap/line layout here.
277 // Using SdrBlockTextPrimitive2D OTOH is critical since it internally
278 // uses the SdrObject it references. To solve this, create a temp
279 // SdrObject with Attributes and Text, generate a SdrBlockTextPrimitive2D
280 // directly and immediately decompose it. After that, it is no longer
281 // needed and can be deleted.
283 // create temp RectObj as TextObj and set needed attributes
284 SdrRectObj
aRectObj(OBJ_TEXT
);
285 aRectObj
.SetModel(GetGrafObject().GetModel());
286 aRectObj
.NbcSetText(aDraftText
);
287 aRectObj
.SetMergedItem(SvxColorItem(Color(COL_LIGHTRED
), EE_CHAR_COLOR
));
289 // get SdrText and OPO
290 SdrText
* pSdrText
= aRectObj
.getText(0);
291 OutlinerParaObject
* pOPO
= aRectObj
.GetOutlinerParaObject();
295 // directly use the remaining space as TextRangeTransform
296 basegfx::B2DHomMatrix aTextRangeTransform
;
298 aTextRangeTransform
.scale(aScale
.getX(), aScale
.getY());
299 aTextRangeTransform
.shearX(fShearX
);
300 aTextRangeTransform
.rotate(fRotate
);
301 aTextRangeTransform
.translate(aTranslate
.getX(), aTranslate
.getY());
303 // directly create temp SdrBlockTextPrimitive2D
304 drawinglayer::primitive2d::SdrBlockTextPrimitive2D
aBlockTextPrimitive(
308 SDRTEXTHORZADJUST_LEFT
,
309 SDRTEXTVERTADJUST_TOP
,
315 // decompose immediately with neutral ViewInformation. This will
316 // layout the text to more simple TextPrimitives from drawinglayer
317 const drawinglayer::geometry::ViewInformation2D
aViewInformation2D(0);
319 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(
321 aBlockTextPrimitive
.get2DDecomposition(aViewInformation2D
));
328 drawinglayer::primitive2d::Primitive2DSequence
ViewContactOfGraphic::createViewIndependentPrimitive2DSequence() const
330 drawinglayer::primitive2d::Primitive2DSequence xRetval
;
331 SdrText
* pSdrText
= GetGrafObject().getText(0);
335 const SfxItemSet
& rItemSet
= GetGrafObject().GetMergedItemSet();
336 drawinglayer::attribute::SdrLineFillShadowTextAttribute
* pAttribute
=
337 drawinglayer::primitive2d::createNewSdrLineFillShadowTextAttribute(rItemSet
, *pSdrText
);
338 bool bVisible(pAttribute
&& pAttribute
->isVisible());
340 // create and fill GraphicAttr
341 GraphicAttr aLocalGrafInfo
;
342 const sal_uInt16
nTrans(((SdrGrafTransparenceItem
&)rItemSet
.Get(SDRATTR_GRAFTRANSPARENCE
)).GetValue());
343 const SdrGrafCropItem
& rCrop((const SdrGrafCropItem
&)rItemSet
.Get(SDRATTR_GRAFCROP
));
344 aLocalGrafInfo
.SetLuminance(((SdrGrafLuminanceItem
&)rItemSet
.Get(SDRATTR_GRAFLUMINANCE
)).GetValue());
345 aLocalGrafInfo
.SetContrast(((SdrGrafContrastItem
&)rItemSet
.Get(SDRATTR_GRAFCONTRAST
)).GetValue());
346 aLocalGrafInfo
.SetChannelR(((SdrGrafRedItem
&)rItemSet
.Get(SDRATTR_GRAFRED
)).GetValue());
347 aLocalGrafInfo
.SetChannelG(((SdrGrafGreenItem
&)rItemSet
.Get(SDRATTR_GRAFGREEN
)).GetValue());
348 aLocalGrafInfo
.SetChannelB(((SdrGrafBlueItem
&)rItemSet
.Get(SDRATTR_GRAFBLUE
)).GetValue());
349 aLocalGrafInfo
.SetGamma(((SdrGrafGamma100Item
&)rItemSet
.Get(SDRATTR_GRAFGAMMA
)).GetValue() * 0.01);
350 aLocalGrafInfo
.SetTransparency((BYTE
)::basegfx::fround(Min(nTrans
, (USHORT
)100) * 2.55));
351 aLocalGrafInfo
.SetInvert(((SdrGrafInvertItem
&)rItemSet
.Get(SDRATTR_GRAFINVERT
)).GetValue());
352 aLocalGrafInfo
.SetDrawMode(((SdrGrafModeItem
&)rItemSet
.Get(SDRATTR_GRAFMODE
)).GetValue());
353 aLocalGrafInfo
.SetCrop(rCrop
.GetLeft(), rCrop
.GetTop(), rCrop
.GetRight(), rCrop
.GetBottom());
355 if(!bVisible
&& 255L != aLocalGrafInfo
.GetTransparency())
357 // content is visible, so force some fill stuff
362 drawinglayer::attribute::SdrShadowAttribute
* pShadow
= drawinglayer::primitive2d::createNewSdrShadowAttribute(rItemSet
);
364 if(pShadow
&& !pShadow
->isVisible())
370 // create new attribute set
371 pAttribute
= new drawinglayer::attribute::SdrLineFillShadowTextAttribute(0L, 0L, 0L, pShadow
, 0L, 0L);
376 if(pAttribute
->isVisible() || bVisible
)
378 // take unrotated snap rect for position and size. Directly use model data, not getBoundRect() or getSnapRect()
379 // which will use the primitive data we just create in the near future
380 const Rectangle
& rRectangle
= GetGrafObject().GetGeoRect();
381 const ::basegfx::B2DRange
aObjectRange(rRectangle
.Left(), rRectangle
.Top(), rRectangle
.Right(), rRectangle
.Bottom());
382 basegfx::B2DHomMatrix aObjectMatrix
;
384 // look for mirroring
385 const GeoStat
& rGeoStat(GetGrafObject().GetGeoStat());
386 const sal_Int32
nDrehWink(rGeoStat
.nDrehWink
);
387 const bool bRota180(18000 == nDrehWink
);
388 const bool bMirrored(GetGrafObject().IsMirrored());
389 const sal_uInt16
nMirrorCase(bRota180
? (bMirrored
? 3 : 4) : (bMirrored
? 2 : 1));
390 bool bHMirr((2 == nMirrorCase
) || (4 == nMirrorCase
));
391 bool bVMirr((3 == nMirrorCase
) || (4 == nMirrorCase
));
393 // set mirror flags at LocalGrafInfo. Take into account that the geometry in
394 // aObjectRange is already changed and rotated when bRota180 is used. To rebuild
395 // that old behaviour (as long as part of the model data), correct the H/V flags
396 // accordingly. The created bitmapPrimitive WILL use the rotation, too.
399 // if bRota180 which is used for vertical mirroring, the graphic will already be rotated
400 // by 180 degrees. To correct, switch off VMirror and invert HMirroring.
407 aLocalGrafInfo
.SetMirrorFlags((bHMirr
? BMP_MIRROR_HORZ
: 0)|(bVMirr
? BMP_MIRROR_VERT
: 0));
410 // fill object matrix
411 const double fShearX(rGeoStat
.nShearWink
? tan((36000 - rGeoStat
.nShearWink
) * F_PI18000
) : 0.0);
412 const double fRotate(nDrehWink
? (36000 - nDrehWink
) * F_PI18000
: 0.0);
413 aObjectMatrix
.scale(aObjectRange
.getWidth(), aObjectRange
.getHeight());
414 aObjectMatrix
.shearX(fShearX
);
415 aObjectMatrix
.rotate(fRotate
);
416 aObjectMatrix
.translate(aObjectRange
.getMinX(), aObjectRange
.getMinY());
418 // get the current, unchenged graphic obect from SdrGrafObj
419 const GraphicObject
& rGraphicObject
= GetGrafObject().GetGraphicObject(false);
421 if(visualisationUsesPresObj())
423 // it's an EmptyPresObj, create the SdrGrafPrimitive2D without content and another scaled one
424 // with the content which is the placeholder graphic
425 xRetval
= createVIP2DSForPresObj(aObjectMatrix
, *pAttribute
, aLocalGrafInfo
);
427 else if(visualisationUsesDraft())
429 // #i102380# The graphic is swapped out. To not force a swap-in here, there is a mechanism
430 // which shows a swapped-out-visualisation (which gets created here now) and an asynchronious
431 // visual update mechanism for swapped-out grapgics when they were loaded (see AsynchGraphicLoadingEvent
432 // and ViewObjectContactOfGraphic implementation). Not forcing the swap-in here allows faster
433 // (non-blocking) processing here and thus in the effect e.g. fast scrolling through pages
434 xRetval
= createVIP2DSForDraft(aObjectMatrix
, *pAttribute
);
438 // create primitive. Info: Calling the copy-constructor of GraphicObject in this
439 // SdrGrafPrimitive2D constructor will force a full swap-in of the graphic
440 const drawinglayer::primitive2d::Primitive2DReference
xReference(new drawinglayer::primitive2d::SdrGrafPrimitive2D(
446 xRetval
= drawinglayer::primitive2d::Primitive2DSequence(&xReference
, 1);
457 bool ViewContactOfGraphic::visualisationUsesPresObj() const
459 return GetGrafObject().IsEmptyPresObj();
462 bool ViewContactOfGraphic::visualisationUsesDraft() const
464 // no draft when already PresObj
465 if(visualisationUsesPresObj())
468 // draft when swapped out
469 const GraphicObject
& rGraphicObject
= GetGrafObject().GetGraphicObject(false);
470 static bool bAllowReplacements(true);
472 if(rGraphicObject
.IsSwappedOut() && bAllowReplacements
)
475 // draft when no graphic
476 if(GRAPHIC_NONE
== rGraphicObject
.GetType() || GRAPHIC_DEFAULT
== rGraphicObject
.GetType())
482 } // end of namespace contact
483 } // end of namespace sdr
485 //////////////////////////////////////////////////////////////////////////////