/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// MM02 needed for VOC mechanism and getting the OC - may be moved to an own file #include <svx/sdrpagewindow.hxx> #include <svx/svdoutl.hxx> #include <svx/svdpage.hxx> #include <svx/svdpagv.hxx> #include <svx/unopage.hxx> #include <svx/sdr/contact/viewcontact.hxx> #include <svx/sdr/contact/viewobjectcontact.hxx> #include <svx/sdr/contact/objectcontact.hxx> #include <svx/sdr/contact/displayinfo.hxx>
// #i13147# - add 2nd parameter with value <true> to // method call <FindFlyFrame().GetContour(..)> to indicate that it is called // for paint in order to avoid load of the intrinsic graphic. if ( ( !rRenderContext.GetConnectMetaFile() ||
!pSh->GetWin() ) &&
FindFlyFrame()->GetContour( aPoly, true )
)
{ // don't clip if related compatibility flag is set const IDocumentSettingAccess& rIDSA = pSh->GetDoc()->getIDocumentSettingAccess(); if (!rIDSA.get(DocumentSettingId::NO_CLIPPING_WITH_WRAP_POLYGON))
rRenderContext.SetClipRegion(vcl::Region(aPoly));
bClip = false;
}
/** Calculate the Bitmap's position and the size within the passed rectangle */ void SwNoTextFrame::GetGrfArea( SwRect &rRect, SwRect* pOrigRect ) const
{ // Currently only used for scaling, cropping and mirroring the contour of graphics! // Everything else is handled by GraphicObject // We put the graphic's visible rectangle into rRect. // pOrigRect contains position and size of the whole graphic.
// RotateFlyFrame3: SwFrame may be transformed. Get untransformed // SwRect(s) as base of calculation const TransformableSwFrame* pTransformableSwFrame(getTransformableSwFrame()); const SwRect aFrameArea(pTransformableSwFrame ? pTransformableSwFrame->getUntransformedFrameArea() : getFrameArea()); const SwRect aFramePrintArea(pTransformableSwFrame ? pTransformableSwFrame->getUntransformedFramePrintArea() : getFramePrintArea());
/** By returning the surrounding Fly's size which equals the graphic's size */ const Size& SwNoTextFrame::GetSize() const
{ // Return the Frame's size const SwFrame *pFly = FindFlyFrame(); if( !pFly )
pFly = this; return pFly->getFramePrintArea().SSize();
}
void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
{ // RotateFlyFrame3 - inner frame. Get rotation and check if used constdouble fRotation(getLocalFrameRotation()); constbool bRotated(!basegfx::fTools::equalZero(fRotation));
if(pUpperFly)
{ if(!pUpperFly->isFrameAreaDefinitionValid())
{ // RotateFlyFrame3: outer frame *needs* to be layouted first, force this by calling // it's ::Calc directly
pUpperFly->Calc(pRenderContext);
}
// Reset outer frame to unrotated state. This is necessary to make the // layouting below work as currently implemented in Writer. As expected // using Transformations allows to do this on the fly due to all information // being included there. // The full solution would be to adapt the whole layouting // process of Writer to take care of Transformations, but that // is currently beyond scope if(pUpperFly->isTransformableSwFrame())
{
pUpperFly->getTransformableSwFrame()->restoreFrameAreas();
}
}
// Re-layout may be partially (see all isFrameAreaDefinitionValid() flags), // so resetting the local SwFrame(s) in the local SwFrameAreaDefinition is also // needed (e.g. for PrintPreview). // Reset to BoundAreas will be done below automatically if(isTransformableSwFrame())
{
getTransformableSwFrame()->restoreFrameAreas();
}
}
SwContentNotify aNotify( this );
SwBorderAttrAccess aAccess( SwFrame::GetCache(), this ); const SwBorderAttrs &rAttrs = *aAccess.Get();
while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
{
MakePos();
if(pUpperFly)
{ // restore outer frame back to Transformed state, that means // set the SwFrameAreaDefinition(s) back to BoundAreas of // the transformed SwFrame. All needed information is part // of the already correctly created Transformations of the // upper frame, so it can be re-created on the fly if(pUpperFly->isTransformableSwFrame())
{
pUpperFly->getTransformableSwFrame()->adaptFrameAreasToTransformations();
}
}
// After the unrotated layout is finished, apply possible set rotation to it // get center from outer frame (layout frame) to be on the safe side const Point aCenter(GetUpper() ? GetUpper()->getFrameArea().Center() : getFrameArea().Center()); const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
getTransformableSwFrame()->createFrameAreaTransformations(
fRotation,
aB2DCenter);
getTransformableSwFrame()->adaptFrameAreasToTransformations();
} else
{ // reset transformations to show that they are not used
mpTransformableSwFrame.reset();
}
}
// RotateFlyFrame3 - Support for Transformations - outer frame
basegfx::B2DHomMatrix SwNoTextFrame::getFrameAreaTransformation() const
{ if(isTransformableSwFrame())
{ // use pre-created transformation return getTransformableSwFrame()->getLocalFrameAreaTransformation();
}
// RotateFlyFrame3 - Support for Transformations void SwNoTextFrame::transform_translate(const Point& rOffset)
{ // call parent - this will do the basic transform for SwRect(s) // in the SwFrameAreaDefinition
SwContentFrame::transform_translate(rOffset);
// check if the Transformations need to be adapted if(isTransformableSwFrame())
{ const basegfx::B2DHomMatrix aTransform(
basegfx::utils::createTranslateB2DHomMatrix(
rOffset.X(), rOffset.Y()));
// transform using TransformableSwFrame
getTransformableSwFrame()->transform(aTransform);
}
}
// RotateFlyFrame3 - inner frame // Check if we contain a SwGrfNode and get possible rotation from it double SwNoTextFrame::getLocalFrameRotation() const
{ const SwNoTextNode* pSwNoTextNode(nullptr != GetNode() ? GetNode()->GetNoTextNode() : nullptr);
// Is the Bitmap in the visible area at all? if( !aFrameRect.Overlaps( rRect ) )
{ // If not, then the Cursor is on the Frame
rRect = aFrameRect;
rRect.Width( 1 );
} else
rRect.Intersection_( aFrameRect );
if ( pCMS && pCMS->m_bRealHeight )
{
pCMS->m_aRealHeight.setY(rRect.Height());
pCMS->m_aRealHeight.setX(0);
}
sal_uInt16 n; for( n = RES_GRFATR_BEGIN; n < RES_GRFATR_END; ++n ) if( SfxItemState::SET == pChangeHint->m_pOld->GetChgSet()->
GetItemState( n, false ))
{
ClearCache();
if(RES_GRFATR_ROTATION == n)
{ // RotGrfFlyFrame: Update Handles in view, these may be rotation-dependent // (e.g. crop handles) and need a visualisation update if ( GetNode()->GetNodeType() == SwNodeType::Grf )
{
SwGrfNode* pNd = static_cast<SwGrfNode*>( GetNode());
SwViewShell *pVSh = pNd->GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell();
// RotateFlyFrame3 - invalidate needed for ContentFrame (inner, this) // and LayoutFrame (outer, GetUpper). It is possible to only invalidate // the outer frame, but that leads to an in-between state that gets // potentially painted if(GetUpper())
{
GetUpper()->InvalidateAll_();
}
InvalidateAll_();
}
} break;
} if( RES_GRFATR_END == n ) // not found return ;
staticbool paintUsingPrimitivesHelper(
vcl::RenderContext& rOutputDevice, const drawinglayer::primitive2d::Primitive2DContainer& rSequence, const basegfx::B2DRange& rSourceRange, const basegfx::B2DRange& rTargetRange)
{ if(!rSequence.empty() && !basegfx::fTools::equalZero(rSourceRange.getWidth()) && !basegfx::fTools::equalZero(rSourceRange.getHeight()))
{ if(!basegfx::fTools::equalZero(rTargetRange.getWidth()) && !basegfx::fTools::equalZero(rTargetRange.getHeight()))
{ // map graphic range to target range. This will e.g. automatically include // the mapping from 1/100th mm content to twips if needed when the target // range is defined in twips const basegfx::B2DHomMatrix aMappingTransform(
basegfx::utils::createSourceRangeTargetRangeTransform(
rSourceRange,
rTargetRange));
// Fill ViewInformation. Use MappingTransform here, so there is no need to // embed the primitives to it. Use original TargetRange here so there is also // no need to embed the primitives to a MaskPrimitive for cropping. This works // only in this case where the graphic object cannot be rotated, though.
drawinglayer::geometry::ViewInformation2D aViewInformation2D;
aViewInformation2D.setObjectTransformation(aMappingTransform);
aViewInformation2D.setViewTransformation(rOutputDevice.GetViewTransformation());
aViewInformation2D.setViewport(rTargetRange);
// get a primitive processor for rendering
std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
drawinglayer::processor2d::createProcessor2DFromOutputDevice(
rOutputDevice, aViewInformation2D) );
// render and cleanup
pProcessor2D->process(rSequence); returntrue;
}
}
returnfalse;
}
// MM02 original using fallback to VOC and primitive-based version void paintGraphicUsingPrimitivesHelper(
vcl::RenderContext & rOutputDevice,
GraphicObject const& rGrfObj,
GraphicAttr const& rGraphicAttr, const basegfx::B2DHomMatrix& rGraphicTransform, const OUString& rName, const OUString& rTitle, const OUString& rDescription)
{ // RotGrfFlyFrame: unify using GraphicPrimitive2D // -> the primitive handles all crop and mirror stuff // -> the primitive renderer will create the needed pdf export data // -> if bitmap content, it will be cached system-dependent
drawinglayer::primitive2d::Primitive2DContainer aContent { new drawinglayer::primitive2d::GraphicPrimitive2D(
rGraphicTransform,
rGrfObj,
rGraphicAttr) };
// MM02 use primitive-based version for visualization
paintGraphicUsingPrimitivesHelper(
rOutputDevice,
aContent,
rGraphicTransform,
rName,
rTitle,
rDescription);
}
// MM02 new VOC and primitive-based version void paintGraphicUsingPrimitivesHelper(
vcl::RenderContext & rOutputDevice,
drawinglayer::primitive2d::Primitive2DContainer& rContent, const basegfx::B2DHomMatrix& rGraphicTransform, const OUString& rName, const OUString& rTitle, const OUString& rDescription)
{ // RotateFlyFrame3: If ClipRegion is set at OutputDevice, we // need to use that. Usually the renderer would be a VCL-based // PrimitiveRenderer, but there are system-specific shortcuts that // will *not* use the VCL-Paint of Bitmap and thus ignore this. // Anyways, indirectly using a CLipRegion set at the target OutDev // when using a PrimitiveRenderer is a non-valid implication. // First tried only to use when HasPolyPolygonOrB2DPolyPolygon(), // but there is an optimization at ClipRegion creation that detects // a single Rectangle in a tools::PolyPolygon and forces to a simple // RegionBand-based implementation, so cannot use it here. if(rOutputDevice.IsClipRegion())
{
basegfx::B2DPolyPolygon aClip(rOutputDevice.GetClipRegion().GetAsB2DPolyPolygon());
if(!rName.isEmpty() || !rTitle.isEmpty() || !rDescription.isEmpty())
{ // Embed to ObjectInfoPrimitive2D when we have Name/Title/Description // information available
rContent = drawinglayer::primitive2d::Primitive2DContainer { new drawinglayer::primitive2d::ObjectInfoPrimitive2D(
std::move(rContent),
rName,
rTitle,
rDescription) };
}
// MM02 this is the right place in the VOC-Mechanism to create // the primitives for visualization - these will be automatically // buffered and reused
rVisitor.visit(new drawinglayer::primitive2d::GraphicPrimitive2D(
aGraphicTransform,
rGrfObj,
aGraphicAttr));
}
}
// calculate aligned rectangle from parameter <rGrfArea>. // Use aligned rectangle <aAlignedGrfArea> instead of <rGrfArea> in // the following code.
SwRect aAlignedGrfArea = rGrfArea;
::SwAlignRect( aAlignedGrfArea, pShell, pOut );
if( !bIsChart )
{ // Because for drawing a graphic left-top-corner and size coordinations are // used, these coordinations have to be determined on pixel level.
::SwAlignGrfRect( &aAlignedGrfArea, *pOut );
} else//if( bIsChart )
{ // #i78025# charts own borders are not completely visible // the above pixel correction is not correct - at least not for charts // so a different pixel correction is chosen here // this might be a good idea for all other OLE objects also, // but as I cannot oversee the consequences I fix it only for charts for now
lcl_correctlyAlignRect( aAlignedGrfArea, rGrfArea, pOut );
}
// #i99665# // Adjust AntiAliasing mode at output device for chart OLE if (pOLENd && pOLENd->IsChart())
nNewAntialiasingAtOutput |= AntialiasingFlags::PixelSnapHairline;
// MM02 To allow system-dependent buffering of the involved // bitmaps it is necessary to re-use the involved primitives // and their already executed decomposition (also for // performance reasons). This is usually done in DrawingLayer // by using the VOC-Mechanism (see descriptions elsewhere). // To get that here, make the involved SwNoTextFrame (this) // a sdr::contact::ViewContact supplier by supporting // a GetViewContact() - call. For ObjectContact we can use // the already existing ObjectContact from the involved // DrawingLayer. For this, the helper classes // ViewObjectContactOfSwNoTextFrame // ViewContactOfSwNoTextFrame // are created which support the VOC-mechanism in its minimal // form. This allows automatic and view-dependent (multiple edit // windows, print, etc.) re-use of the created primitives. // Also: Will be very useful when completely changing the Writer // repaint to VOC and Primitives, too. staticconstchar* pDisableMM02Goodies(getenv("SAL_DISABLE_MM02_GOODIES")); staticbool bUseViewObjectContactMechanism(nullptr == pDisableMM02Goodies); // tdf#130951 for safety reasons use fallback if ViewObjectContactMechanism // fails for some reason - usually could only be not to find the correct // SdrPageWindow bool bSucceeded(false);
if(bUseViewObjectContactMechanism)
{ // MM02 use VOC-mechanism and buffer primitives
SwViewShellImp* pImp(pShell->Imp());
SdrPageView* pPageView(nullptr != pImp
? pImp->GetPageView()
: nullptr); // tdf#130951 caution - target may be Window, use the correct OutputDevice
OutputDevice* pTarget((pShell->isOutputToWindow() && pShell->GetWin())
? pShell->GetWin()->GetOutDev()
: pShell->GetOut());
SdrPageWindow* pPageWindow(nullptr != pPageView && nullptr != pTarget
? pPageView->FindPageWindow(*pTarget)
: nullptr);
if(!bSucceeded)
{ // MM02 fallback to direct paint with primitive-recreation // which will block reusage of system-dependent bitmap data const basegfx::B2DHomMatrix aGraphicTransform(getFrameAreaTransformation());
if (pPage)
pPage->getSdrModelFromSdrPage().GetDrawOutliner().SetBackgroundColor(aOldBackColor);
}
}
if(bDone || !pOLENd) return;
// SwOLENode does not have a known GraphicObject, need to // work with Graphic instead const Graphic* pGraphic = pOLENd->GetGraphic(); const Point aPosition(rAlignedGrfArea.Pos()); const Size aSize(rAlignedGrfArea.SSize());
// RotateFlyFrame3: If we are transformed, there are 'free' areas between // the Graphic and the Border/Padding stuff - at least as long as those // (Border and Padding) are not transformed, too if(isTransformableSwFrame())
{ // we can be more specific - rotations of multiples of // 90 degrees will leave no gaps. Go from [0.0 .. 2PI] // to [0 .. 360] and check modulo 90 const tools::Long nRot(static_cast<tools::Long>(basegfx::rad2deg(getLocalFrameRotation()))); constbool bMultipleOf90(0 == (nRot % 90));
if(!bMultipleOf90)
{ returntrue;
}
}
//#29381# OLE are always transparent if(nullptr != GetNode()->GetOLENode())
{ returntrue;
}
// return false by default to avoid background paint returnfalse;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.93Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.