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 <svx/sdr/contact/viewobjectcontact.hxx>
21 #include <svx/sdr/contact/viewcontact.hxx>
22 #include <svx/sdr/contact/objectcontact.hxx>
23 #include <svx/sdr/contact/displayinfo.hxx>
24 #include <svx/sdr/animation/animationstate.hxx>
25 #include <svx/sdr/contact/viewobjectcontactredirector.hxx>
26 #include <basegfx/color/bcolor.hxx>
27 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
28 #include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
29 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
30 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
31 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
32 #include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
33 #include <svx/svdobj.hxx>
34 #include <svx/svdomedia.hxx>
35 #include <svx/svdmodel.hxx>
36 #include <svx/svdpage.hxx>
37 #include <svx/svdotext.hxx>
38 #include <vcl/pdfwriter.hxx>
39 #include <vcl/pdfextoutdevdata.hxx>
41 using namespace com::sun::star
;
47 // Necessary to filter a sequence of animated primitives from
48 // a sequence of primitives to find out if animated or not. The decision for
49 // what to decompose is hard-coded and only done for knowingly animated primitives
50 // to not decompose too deeply and unnecessarily. This implies that the list
51 // which is view-specific needs to be expanded by hand when new animated objects
52 // are added. This may eventually be changed to a dynamically configurable approach
54 class AnimatedExtractingProcessor2D
: public drawinglayer::processor2d::BaseProcessor2D
57 // the found animated primitives
58 drawinglayer::primitive2d::Primitive2DContainer maPrimitive2DSequence
;
60 // text animation allowed?
61 bool mbTextAnimationAllowed
: 1;
63 // graphic animation allowed?
64 bool mbGraphicAnimationAllowed
: 1;
66 // as tooling, the process() implementation takes over API handling and calls this
67 // virtual render method when the primitive implementation is BasePrimitive2D-based.
68 virtual void processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D
& rCandidate
) override
;
71 AnimatedExtractingProcessor2D(
72 const drawinglayer::geometry::ViewInformation2D
& rViewInformation
,
73 bool bTextAnimationAllowed
,
74 bool bGraphicAnimationAllowed
);
77 const drawinglayer::primitive2d::Primitive2DContainer
& getPrimitive2DSequence() const { return maPrimitive2DSequence
; }
78 drawinglayer::primitive2d::Primitive2DContainer
extractPrimitive2DSequence() { return std::move(maPrimitive2DSequence
); }
81 AnimatedExtractingProcessor2D::AnimatedExtractingProcessor2D(
82 const drawinglayer::geometry::ViewInformation2D
& rViewInformation
,
83 bool bTextAnimationAllowed
,
84 bool bGraphicAnimationAllowed
)
85 : drawinglayer::processor2d::BaseProcessor2D(rViewInformation
),
86 mbTextAnimationAllowed(bTextAnimationAllowed
),
87 mbGraphicAnimationAllowed(bGraphicAnimationAllowed
)
91 void AnimatedExtractingProcessor2D::processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D
& rCandidate
)
93 // known implementation, access directly
94 switch(rCandidate
.getPrimitive2DID())
96 // add and accept animated primitives directly, no need to decompose
97 case PRIMITIVE2D_ID_ANIMATEDSWITCHPRIMITIVE2D
:
98 case PRIMITIVE2D_ID_ANIMATEDBLINKPRIMITIVE2D
:
99 case PRIMITIVE2D_ID_ANIMATEDINTERPOLATEPRIMITIVE2D
:
101 const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D
& rSwitchPrimitive
= static_cast< const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D
& >(rCandidate
);
103 if((rSwitchPrimitive
.isTextAnimation() && mbTextAnimationAllowed
)
104 || (rSwitchPrimitive
.isGraphicAnimation() && mbGraphicAnimationAllowed
))
106 const drawinglayer::primitive2d::Primitive2DReference
xReference(const_cast< drawinglayer::primitive2d::BasePrimitive2D
* >(&rCandidate
));
107 maPrimitive2DSequence
.push_back(xReference
);
112 // decompose animated gifs where SdrGrafPrimitive2D produces a GraphicPrimitive2D
113 // which then produces the animation infos (all when used/needed)
114 case PRIMITIVE2D_ID_SDRGRAFPRIMITIVE2D
:
115 case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D
:
117 // decompose SdrObjects with evtl. animated text
118 case PRIMITIVE2D_ID_SDRCAPTIONPRIMITIVE2D
:
119 case PRIMITIVE2D_ID_SDRCONNECTORPRIMITIVE2D
:
120 case PRIMITIVE2D_ID_SDRCUSTOMSHAPEPRIMITIVE2D
:
121 case PRIMITIVE2D_ID_SDRELLIPSEPRIMITIVE2D
:
122 case PRIMITIVE2D_ID_SDRELLIPSESEGMENTPRIMITIVE2D
:
123 case PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D
:
124 case PRIMITIVE2D_ID_SDRPATHPRIMITIVE2D
:
125 case PRIMITIVE2D_ID_SDRRECTANGLEPRIMITIVE2D
:
127 // #121194# With Graphic as Bitmap FillStyle, also check
128 // for primitives filled with animated graphics
129 case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D
:
130 case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D
:
131 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D
:
133 // decompose evtl. animated text contained in MaskPrimitive2D
134 // or group primitives
135 case PRIMITIVE2D_ID_MASKPRIMITIVE2D
:
136 case PRIMITIVE2D_ID_GROUPPRIMITIVE2D
:
144 // nothing to do for the rest
150 } // end of anonymous namespace
152 namespace sdr::contact
{
154 ViewObjectContact::ViewObjectContact(ObjectContact
& rObjectContact
, ViewContact
& rViewContact
)
155 : mrObjectContact(rObjectContact
),
156 mrViewContact(rViewContact
),
157 maGridOffset(0.0, 0.0),
158 mnActionChangedCount(0),
159 mbLazyInvalidate(false)
161 // make the ViewContact remember me
162 mrViewContact
.AddViewObjectContact(*this);
164 // make the ObjectContact remember me
165 mrObjectContact
.AddViewObjectContact(*this);
168 ViewObjectContact::~ViewObjectContact()
170 // if the object range is empty, then we have never had the primitive range change, so nothing to invalidate
171 if (!maObjectRange
.isEmpty())
173 // invalidate in view
174 if(!getObjectRange().isEmpty())
176 GetObjectContact().InvalidatePartOfView(maObjectRange
);
180 // delete PrimitiveAnimation
181 mpPrimitiveAnimation
.reset();
183 // take care of remembered ObjectContact. Remove from
184 // OC first. The VC removal (below) CAN trigger a StopGettingViewed()
185 // which (depending of its implementation) may destroy other OCs. This
186 // can trigger the deletion of the helper OC of a page visualising object
187 // which IS the OC of this object. Eventually StopGettingViewed() needs
188 // to get asynchron later
189 GetObjectContact().RemoveViewObjectContact(*this);
191 // take care of remembered ViewContact
192 GetViewContact().RemoveViewObjectContact(*this);
195 const basegfx::B2DRange
& ViewObjectContact::getObjectRange() const
197 if(maObjectRange
.isEmpty())
199 const drawinglayer::geometry::ViewInformation2D
& rViewInfo2D
= GetObjectContact().getViewInformation2D();
200 basegfx::B2DRange aTempRange
= GetViewContact().getRange(rViewInfo2D
);
201 if (!aTempRange
.isEmpty())
203 const_cast< ViewObjectContact
* >(this)->maObjectRange
= aTempRange
;
207 // if range is not computed (new or LazyInvalidate objects), force it
208 const DisplayInfo aDisplayInfo
;
209 const drawinglayer::primitive2d::Primitive2DContainer
& xSequence(getPrimitive2DSequence(aDisplayInfo
));
211 if(!xSequence
.empty())
213 const_cast< ViewObjectContact
* >(this)->maObjectRange
=
214 xSequence
.getB2DRange(rViewInfo2D
);
219 return maObjectRange
;
222 void ViewObjectContact::ActionChanged()
224 // clear cached primitives
225 mxPrimitive2DSequence
.clear();
226 ++mnActionChangedCount
;
232 mbLazyInvalidate
= true;
237 if(!getObjectRange().isEmpty())
239 // invalidate current valid range
240 GetObjectContact().InvalidatePartOfView(maObjectRange
);
242 // reset gridOffset, it needs to be recalculated
243 if (GetObjectContact().supportsGridOffsets())
246 maObjectRange
.reset();
249 // register at OC for lazy invalidate
250 GetObjectContact().setLazyInvalidate(*this);
253 void ViewObjectContact::triggerLazyInvalidate()
255 if(!mbLazyInvalidate
)
259 mbLazyInvalidate
= false;
264 if(!getObjectRange().isEmpty())
266 // invalidate current valid range
267 GetObjectContact().InvalidatePartOfView(maObjectRange
);
271 // Take some action when new objects are inserted
272 void ViewObjectContact::ActionChildInserted(ViewContact
& rChild
)
274 // force creation of the new VOC and trigger it's refresh, so it
275 // will take part in LazyInvalidate immediately
276 rChild
.GetViewObjectContact(GetObjectContact()).ActionChanged();
278 // forward action to ObjectContact
279 // const ViewObjectContact& rChildVOC = rChild.GetViewObjectContact(GetObjectContact());
280 // GetObjectContact().InvalidatePartOfView(rChildVOC.getObjectRange());
283 void ViewObjectContact::checkForPrimitive2DAnimations()
286 mpPrimitiveAnimation
.reset();
288 // check for animated primitives
289 if(mxPrimitive2DSequence
.empty())
292 const bool bTextAnimationAllowed(GetObjectContact().IsTextAnimationAllowed());
293 const bool bGraphicAnimationAllowed(GetObjectContact().IsGraphicAnimationAllowed());
295 if(bTextAnimationAllowed
|| bGraphicAnimationAllowed
)
297 AnimatedExtractingProcessor2D
aAnimatedExtractor(GetObjectContact().getViewInformation2D(),
298 bTextAnimationAllowed
, bGraphicAnimationAllowed
);
299 aAnimatedExtractor
.process(mxPrimitive2DSequence
);
301 if(!aAnimatedExtractor
.getPrimitive2DSequence().empty())
303 // derived primitiveList is animated, setup new PrimitiveAnimation
304 mpPrimitiveAnimation
.reset( new sdr::animation::PrimitiveAnimation(*this, aAnimatedExtractor
.extractPrimitive2DSequence()) );
309 void ViewObjectContact::createPrimitive2DSequence(const DisplayInfo
& rDisplayInfo
, drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
) const
311 // get the view-independent Primitive from the viewContact
312 drawinglayer::primitive2d::Primitive2DContainer xRetval
;
313 GetViewContact().getViewIndependentPrimitive2DContainer(xRetval
);
318 if(!GetObjectContact().isOutputToPrinter() && GetObjectContact().AreGluePointsVisible())
320 const drawinglayer::primitive2d::Primitive2DContainer
xGlue(GetViewContact().createGluePointPrimitive2DSequence());
324 xRetval
.append(xGlue
);
329 if(isPrimitiveGhosted(rDisplayInfo
))
331 const basegfx::BColor
aRGBWhite(1.0, 1.0, 1.0);
332 const basegfx::BColorModifierSharedPtr aBColorModifier
=
333 std::make_shared
<basegfx::BColorModifier_interpolate
>(
336 drawinglayer::primitive2d::Primitive2DReference
xReference(
337 new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
341 xRetval
= drawinglayer::primitive2d::Primitive2DContainer
{ xReference
};
345 rVisitor
.visit(xRetval
);
348 bool ViewObjectContact::isExportPDFTags() const
350 return GetObjectContact().isExportTaggedPDF();
353 /** Check if we need to embed to a StructureTagPrimitive2D, too. This
354 was done at ImplRenderPaintProc::createRedirectedPrimitive2DSequence before
356 void ViewObjectContact::createStructureTag(drawinglayer::primitive2d::Primitive2DContainer
& rNewPrimitiveSequence
) const
358 SdrObject
*const pSdrObj(mrViewContact
.TryToGetSdrObject());
360 // Check if we need to embed to a StructureTagPrimitive2D, too. This
361 // was done at ImplRenderPaintProc::createRedirectedPrimitive2DSequence before
362 if (!rNewPrimitiveSequence
.empty() && isExportPDFTags()
363 // ISO 14289-1:2014, Clause: 7.3
364 && (!pSdrObj
|| pSdrObj
->getParentSdrObjectFromSdrObject() == nullptr))
366 if (nullptr != pSdrObj
&& !pSdrObj
->IsDecorative())
368 vcl::PDFWriter::StructElement
eElement(vcl::PDFWriter::NonStructElement
);
369 const SdrInventor
nInventor(pSdrObj
->GetObjInventor());
370 const SdrObjKind
nIdentifier(pSdrObj
->GetObjIdentifier());
371 const bool bIsTextObj(nullptr != DynCastSdrTextObj(pSdrObj
));
373 // Note: SwFlyDrawObj/SwVirtFlyDrawObj have SdrInventor::Swg - these
374 // are *not* handled here because not all of them are painted
375 // completely with primitives, so a tag here does not encapsulate them.
376 // The tag must be created by SwTaggedPDFHelper until this is fixed.
377 if ( nInventor
== SdrInventor::Default
)
379 if ( nIdentifier
== SdrObjKind::Group
)
380 eElement
= vcl::PDFWriter::Figure
;
381 else if (nIdentifier
== SdrObjKind::Table
)
382 eElement
= vcl::PDFWriter::Table
;
383 else if (nIdentifier
== SdrObjKind::Media
)
384 eElement
= vcl::PDFWriter::Annot
;
385 else if ( nIdentifier
== SdrObjKind::TitleText
)
386 eElement
= vcl::PDFWriter::Heading
;
387 else if ( nIdentifier
== SdrObjKind::OutlineText
)
388 eElement
= vcl::PDFWriter::Division
;
389 else if ( !bIsTextObj
|| !static_cast<const SdrTextObj
&>(*pSdrObj
).HasText() )
390 eElement
= vcl::PDFWriter::Figure
;
392 eElement
= vcl::PDFWriter::Division
;
395 if(vcl::PDFWriter::NonStructElement
!= eElement
)
397 SdrPage
* pSdrPage(pSdrObj
->getSdrPageFromSdrObject());
401 const bool bBackground(pSdrPage
->IsMasterPage());
402 const bool bImage(SdrObjKind::Graphic
== pSdrObj
->GetObjIdentifier());
403 // note: there must be output device here, in PDF export
404 void const* pAnchorKey(nullptr);
405 if (auto const pUserCall
= pSdrObj
->GetUserCall())
407 pAnchorKey
= pUserCall
->GetPDFAnchorStructureElementKey(*pSdrObj
);
410 ::std::vector
<sal_Int32
> annotIds
;
411 if (eElement
== vcl::PDFWriter::Annot
412 && !static_cast<SdrMediaObj
*>(pSdrObj
)->getURL().isEmpty())
414 auto const pPDFExtOutDevData(GetObjectContact().GetPDFExtOutDevData());
415 assert(pPDFExtOutDevData
);
416 annotIds
= pPDFExtOutDevData
->GetScreenAnnotIds(pSdrObj
);
419 drawinglayer::primitive2d::Primitive2DReference
xReference(
420 new drawinglayer::primitive2d::StructureTagPrimitive2D(
424 std::move(rNewPrimitiveSequence
),
427 rNewPrimitiveSequence
= drawinglayer::primitive2d::Primitive2DContainer
{ xReference
};
433 // page backgrounds etc should be tagged as artifacts:
434 rNewPrimitiveSequence
= drawinglayer::primitive2d::Primitive2DContainer
{
435 new drawinglayer::primitive2d::StructureTagPrimitive2D(
436 // lies to force silly VclMetafileProcessor2D to emit NonStructElement
437 vcl::PDFWriter::Division
,
440 std::move(rNewPrimitiveSequence
))
446 drawinglayer::primitive2d::Primitive2DContainer
const & ViewObjectContact::getPrimitive2DSequence(const DisplayInfo
& rDisplayInfo
) const
448 // only some of the top-level apps are any good at reliably invalidating us (e.g. writer is not)
449 SdrObject
* pSdrObj(mrViewContact
.TryToGetSdrObject());
451 if (nullptr != pSdrObj
&& pSdrObj
->getSdrModelFromSdrObject().IsVOCInvalidationIsReliable())
453 if (!mxPrimitive2DSequence
.empty())
454 return mxPrimitive2DSequence
;
457 // prepare new representation
458 drawinglayer::primitive2d::Primitive2DContainer xNewPrimitiveSequence
;
460 // take care of redirectors and create new list
461 ViewObjectContactRedirector
* pRedirector
= GetObjectContact().GetViewObjectContactRedirector();
465 pRedirector
->createRedirectedPrimitive2DSequence(*this, rDisplayInfo
, xNewPrimitiveSequence
);
469 createPrimitive2DSequence(rDisplayInfo
, xNewPrimitiveSequence
);
472 // check and eventually embed to GridOffset transform primitive (calc only)
473 if(!xNewPrimitiveSequence
.empty() && GetObjectContact().supportsGridOffsets())
475 const basegfx::B2DVector
& rGridOffset(getGridOffset());
477 if(0.0 != rGridOffset
.getX() || 0.0 != rGridOffset
.getY())
479 const basegfx::B2DHomMatrix
aTranslateGridOffset(
480 basegfx::utils::createTranslateB2DHomMatrix(
482 drawinglayer::primitive2d::Primitive2DReference
aEmbed(
483 new drawinglayer::primitive2d::TransformPrimitive2D(
484 aTranslateGridOffset
,
485 std::move(xNewPrimitiveSequence
)));
486 xNewPrimitiveSequence
= drawinglayer::primitive2d::Primitive2DContainer
{ aEmbed
};
490 createStructureTag(xNewPrimitiveSequence
);
492 // Local up-to-date checks. New list different from local one?
493 // This is the important point where it gets decided if the current or the new
494 // representation gets used. This is important for performance, since the
495 // current representation contains possible precious decompositions. That
496 // comparisons triggers exactly if something in the object visualization
498 // Note: That is the main reason for BasePrimitive2D::operator== at all. I
499 // have alternatively tried to invalidate the local representation on object
500 // change, but that is simply not reliable.
501 // Note2: I did that once in aw080, the lost CWS, and it worked well enough
502 // so that I could remove *all* operator== from all derivations of
503 // BasePrimitive2D, so it can be done again (with the needed resources)
504 if(mxPrimitive2DSequence
!= xNewPrimitiveSequence
)
506 // has changed, copy content
507 const_cast< ViewObjectContact
* >(this)->mxPrimitive2DSequence
= std::move(xNewPrimitiveSequence
);
509 // check for animated stuff
510 const_cast< ViewObjectContact
* >(this)->checkForPrimitive2DAnimations();
512 // always update object range when PrimitiveSequence changes
513 const drawinglayer::geometry::ViewInformation2D
& rViewInformation2D(GetObjectContact().getViewInformation2D());
514 const_cast< ViewObjectContact
* >(this)->maObjectRange
= mxPrimitive2DSequence
.getB2DRange(rViewInformation2D
);
517 // return current Primitive2DContainer
518 return mxPrimitive2DSequence
;
521 bool ViewObjectContact::isPrimitiveVisible(const DisplayInfo
& /*rDisplayInfo*/) const
523 // default: always visible
527 bool ViewObjectContact::isPrimitiveGhosted(const DisplayInfo
& rDisplayInfo
) const
529 // default: standard check
530 return (GetObjectContact().DoVisualizeEnteredGroup() && !GetObjectContact().isOutputToPrinter() && rDisplayInfo
.IsGhostedDrawModeActive());
533 void ViewObjectContact::getPrimitive2DSequenceHierarchy(DisplayInfo
& rDisplayInfo
, drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
) const
535 // check model-view visibility
536 if(!isPrimitiveVisible(rDisplayInfo
))
539 getPrimitive2DSequence(rDisplayInfo
);
540 if(mxPrimitive2DSequence
.empty())
544 const drawinglayer::geometry::ViewInformation2D
& rViewInformation2D(GetObjectContact().getViewInformation2D());
545 // tdf#147164 cannot use maObjectRange here, it is unreliable
546 const basegfx::B2DRange
aObjectRange(mxPrimitive2DSequence
.getB2DRange(rViewInformation2D
));
547 const basegfx::B2DRange
& aViewRange(rViewInformation2D
.getViewport());
549 // check geometrical visibility
550 bool bVisible
= aViewRange
.isEmpty() || aViewRange
.overlaps(aObjectRange
);
554 // temporarily take over the mxPrimitive2DSequence, in case it gets invalidated while we want to iterate over it
555 auto tmp
= std::move(const_cast<ViewObjectContact
*>(this)->mxPrimitive2DSequence
);
556 int nPrevCount
= mnActionChangedCount
;
560 // if we received ActionChanged() calls while walking the primitives, then leave it empty, otherwise move it back
561 if (mnActionChangedCount
== nPrevCount
)
562 const_cast<ViewObjectContact
*>(this)->mxPrimitive2DSequence
= std::move(tmp
);
565 void ViewObjectContact::getPrimitive2DSequenceSubHierarchy(DisplayInfo
& rDisplayInfo
, drawinglayer::primitive2d::Primitive2DDecompositionVisitor
& rVisitor
) const
567 ViewContact
& rViewContact
= GetViewContact();
568 const sal_uInt32
nSubHierarchyCount(rViewContact
.GetObjectCount());
570 for(sal_uInt32
a(0); a
< nSubHierarchyCount
; a
++)
571 rViewContact
.getPrimitive2DSequenceHierarchyOfIndex(a
, rDisplayInfo
, GetObjectContact(), rVisitor
);
574 // Support getting a GridOffset per object and view for non-linear ViewToDevice
575 // transformation (calc). On-demand created by delegating to the ObjectContact
576 // (->View) that has then all needed information
577 const basegfx::B2DVector
& ViewObjectContact::getGridOffset() const
579 if (GetObjectContact().supportsGridOffsets())
581 if (fabs(maGridOffset
.getX()) > 1000.0)
583 // Huge offsets are a hint for error -> usually the conditions for
584 // calculation have changed. E.g. - I saw errors with +/-5740, that
585 // was in the environment of massive external UNO API using LO as
587 // If conditions for this calculation change, it is usually required to call
588 // - ViewObjectContact::resetGridOffset(), or
589 // - ObjectContact::resetAllGridOffsets() or
590 // - ScDrawView::resetGridOffsetsForAllSdrPageViews()
591 // as it is done e.g. when zoom changes (see ScDrawView::RecalcScale()).
592 // Theoretically these resets have to be done for any precondition
593 // changed that is used in the calculation of that value (see
594 // ScDrawView::calculateGridOffsetForSdrObject).
595 // This is not complete and would be hard to do so.
596 // Since it is just a buffered value and re-calculation is not
597 // expensive (linear O(n)) we can just reset suspicious values here.
598 // Hopefully - when that non-linear ViewTransformation problem for
599 // the calc-view gets solved one day - all this can be removed
600 // again. For now, let's just reset here and force re-calculation.
601 // Add a SAL_WARN to inform about this.
602 SAL_WARN("svx", "Suspicious GridOffset value resetted (!)");
603 const_cast<ViewObjectContact
*>(this)->maGridOffset
.setX(0.0);
604 const_cast<ViewObjectContact
*>(this)->maGridOffset
.setY(0.0);
607 if(0.0 == maGridOffset
.getX() && 0.0 == maGridOffset
.getY() && GetObjectContact().supportsGridOffsets())
610 GetObjectContact().calculateGridOffsetForViewObjectContact(const_cast<ViewObjectContact
*>(this)->maGridOffset
, *this);
617 void ViewObjectContact::resetGridOffset()
619 // reset buffered GridOffset itself
620 maGridOffset
.setX(0.0);
621 maGridOffset
.setY(0.0);
623 // also reset sequence to get a re-calculation when GridOffset changes
624 mxPrimitive2DSequence
.clear();
625 maObjectRange
.reset();
630 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */