/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_svx.hxx" #include #include #include #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////// namespace sdr { namespace contact { ViewContactOfSdrObjCustomShape::ViewContactOfSdrObjCustomShape(SdrObjCustomShape& rCustomShape) : ViewContactOfTextObj(rCustomShape) { } ViewContactOfSdrObjCustomShape::~ViewContactOfSdrObjCustomShape() { } basegfx::B2DRange ViewContactOfSdrObjCustomShape::getCorrectedTextBoundRect() const { const Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect()); Rectangle aTextBound(aObjectBound); GetCustomShapeObj().GetTextBounds(aTextBound); basegfx::B2DRange aTextRange(aTextBound.Left(), aTextBound.Top(), aTextBound.Right(), aTextBound.Bottom()); const basegfx::B2DRange aObjectRange(aObjectBound.Left(), aObjectBound.Top(), aObjectBound.Right(), aObjectBound.Bottom()); // no need to correct if no extra text range if(aTextRange != aObjectRange) { const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat()); // only correct when rotation and/or shear is used if(rGeoStat.nShearWink || rGeoStat.nDrehWink ) { // text range needs to be corrected by // aObjectRange.getCenter() - aRotObjectRange.getCenter() since it's // defined differenly by using rotation around object center. Start // with positive part basegfx::B2DVector aTranslation(aObjectRange.getCenter()); // get rotated and sheared object's range basegfx::B2DRange aRotObjectRange(aObjectRange); basegfx::B2DHomMatrix aRotMatrix; aRotMatrix.translate(-aObjectRange.getMinimum().getX(), -aObjectRange.getMinimum().getY()); if(rGeoStat.nShearWink) { aRotMatrix.shearX(tan((36000 - rGeoStat.nShearWink) * F_PI18000)); } if(rGeoStat.nDrehWink) { aRotMatrix.rotate((36000 - rGeoStat.nDrehWink) * F_PI18000); } aRotMatrix.translate(aObjectRange.getMinimum().getX(), aObjectRange.getMinimum().getY()); aRotObjectRange.transform(aRotMatrix); // add negative translation part aTranslation -= aRotObjectRange.getCenter(); // create new range aTextRange = basegfx::B2DRange( aTextRange.getMinX() + aTranslation.getX(), aTextRange.getMinY() + aTranslation.getY(), aTextRange.getMaxX() + aTranslation.getX(), aTextRange.getMaxY() + aTranslation.getY()); } } return aTextRange; } drawinglayer::primitive2d::Primitive2DSequence ViewContactOfSdrObjCustomShape::createViewIndependentPrimitive2DSequence() const { drawinglayer::primitive2d::Primitive2DSequence xRetval; const SfxItemSet& rItemSet = GetCustomShapeObj().GetMergedItemSet(); // #i98072# Get shandow and text; eventually suppress the text if it's // a TextPath FontworkGallery object const drawinglayer::attribute::SdrShadowTextAttribute aAttribute( drawinglayer::primitive2d::createNewSdrShadowTextAttribute( rItemSet, GetCustomShapeObj().getText(0), GetCustomShapeObj().IsTextPath())); drawinglayer::primitive2d::Primitive2DSequence xGroup; bool bHasText(!aAttribute.getText().isDefault()); // create Primitive2DSequence from sub-geometry const SdrObject* pSdrObjRepresentation = GetCustomShapeObj().GetSdrObjectFromCustomShape(); bool b3DShape(false); if(pSdrObjRepresentation) { SdrObjListIter aIterator(*pSdrObjRepresentation); while(aIterator.IsMore()) { SdrObject& rCandidate = *aIterator.Next(); if(!b3DShape && dynamic_cast< E3dObject* >(&rCandidate)) { b3DShape = true; } const drawinglayer::primitive2d::Primitive2DSequence xNew(rCandidate.GetViewContact().getViewIndependentPrimitive2DSequence()); drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xGroup, xNew); } } if(bHasText || xGroup.hasElements()) { // prepare text box geometry basegfx::B2DHomMatrix aTextBoxMatrix; bool bWordWrap(false); if(bHasText) { // take unrotated snap rect as default, then get the // unrotated text box. Rotation needs to be done centered const Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect()); const basegfx::B2DRange aObjectRange(aObjectBound.Left(), aObjectBound.Top(), aObjectBound.Right(), aObjectBound.Bottom()); // #i101684# get the text range unrotated and absolute to the object range const basegfx::B2DRange aTextRange(getCorrectedTextBoundRect()); // give text object a size aTextBoxMatrix.scale(aTextRange.getWidth(), aTextRange.getHeight()); // check if we have a rotation/shear at all to take care of const double fExtraTextRotation(GetCustomShapeObj().GetExtraTextRotation()); const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat()); if(rGeoStat.nShearWink || rGeoStat.nDrehWink || !basegfx::fTools::equalZero(fExtraTextRotation)) { if(aObjectRange != aTextRange) { // move relative to unrotated object range aTextBoxMatrix.translate( aTextRange.getMinX() - aObjectRange.getMinimum().getX(), aTextRange.getMinY() - aObjectRange.getMinimum().getY()); } if(!basegfx::fTools::equalZero(fExtraTextRotation)) { basegfx::B2DVector aTranslation( ( aTextRange.getWidth() / 2 ) + ( aTextRange.getMinX() - aObjectRange.getMinimum().getX() ), ( aTextRange.getHeight() / 2 ) + ( aTextRange.getMinY() - aObjectRange.getMinimum().getY() ) ); aTextBoxMatrix.translate( -aTranslation.getX(), -aTranslation.getY() ); aTextBoxMatrix.rotate((360.0 - fExtraTextRotation) * F_PI180); aTextBoxMatrix.translate( aTranslation.getX(), aTranslation.getY() ); } if(rGeoStat.nShearWink) { aTextBoxMatrix.shearX(tan((36000 - rGeoStat.nShearWink) * F_PI18000)); } if(rGeoStat.nDrehWink) { aTextBoxMatrix.rotate((36000 - rGeoStat.nDrehWink) * F_PI18000); } // give text it's target position aTextBoxMatrix.translate(aObjectRange.getMinimum().getX(), aObjectRange.getMinimum().getY()); } else { aTextBoxMatrix.translate(aTextRange.getMinX(), aTextRange.getMinY()); } // check if SdrTextWordWrapItem is set bWordWrap = ((SdrTextWordWrapItem&)(GetCustomShapeObj().GetMergedItem(SDRATTR_TEXT_WORDWRAP))).GetValue(); } // create primitive const drawinglayer::primitive2d::Primitive2DReference xReference( new drawinglayer::primitive2d::SdrCustomShapePrimitive2D( aAttribute, xGroup, aTextBoxMatrix, bWordWrap, b3DShape, false)); // #SJ# New parameter to force to clipped BlockText for SC xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); } // #119863# always append an invisible outline for the cases where no visible content exists if(true) { const Rectangle aObjectBound(GetCustomShapeObj().GetGeoRect()); const basegfx::B2DRange aObjectRange( aObjectBound.Left(), aObjectBound.Top(), aObjectBound.Right(), aObjectBound.Bottom()); // create object matrix const GeoStat& rGeoStat(GetCustomShapeObj().GetGeoStat()); const double fShearX(rGeoStat.nShearWink ? tan((36000 - rGeoStat.nShearWink) * F_PI18000) : 0.0); const double fRotate(rGeoStat.nDrehWink ? (36000 - rGeoStat.nDrehWink) * F_PI18000 : 0.0); const basegfx::B2DHomMatrix aObjectMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( aObjectRange.getWidth(), aObjectRange.getHeight(), fShearX, fRotate, aObjectRange.getMinX(), aObjectRange.getMinY())); drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, drawinglayer::primitive2d::createHiddenGeometryPrimitives2D( false, aObjectMatrix)); } return xRetval; } } // end of namespace contact } // end of namespace sdr ////////////////////////////////////////////////////////////////////////////// // eof