/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: impgrfll.cxx,v $ * $Revision: 1.16 $ * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_svx.hxx" #include #include // FRound #include #include #include #include #include #include #include #include #include #include #include #include "xattr.hxx" #include "xoutbmp.hxx" #include #include #include #include #include #include #include "svdoimp.hxx" #include /////////////////////////////////////////////////////////////////////////////// #define ITEMVALUE(ItemSet,Id,Cast) ((const Cast&)(ItemSet).Get(Id)).GetValue() //////////////////////////////////////////////////////////////////////////////////////////////////// // #100127# Bracket filled output with a comment, if recording a Mtf ImpGraphicFill::ImpGraphicFill( const SdrObject& rObj, const XOutputDevice& rXOut, const SfxItemSet& rFillItemSet, bool bIsShadow ) : mrXOut( rXOut ), mbCommentWritten( false ) { basegfx::B2DPolyPolygon aGeometry(rObj.TakeXorPoly(sal_True)); prepare( rXOut, rObj.GetMergedItemSet(), aGeometry, rFillItemSet, bIsShadow ); } ImpGraphicFill::ImpGraphicFill( const XOutputDevice& rXOut, const SfxItemSet& rSet, basegfx::B2DPolyPolygon& aGeometry, const SfxItemSet& rFillItemSet, bool bIsShadow ) : mrXOut( rXOut ), mbCommentWritten( false ) { prepare( rXOut, rSet, aGeometry, rFillItemSet, bIsShadow ); } void ImpGraphicFill::prepare( const XOutputDevice& rXOut, const SfxItemSet& rSet, basegfx::B2DPolyPolygon& aGeometry, const SfxItemSet& rFillItemSet, bool bIsShadow ) { XFillStyle eFillStyle( ITEMVALUE( rFillItemSet, XATTR_FILLSTYLE, XFillStyleItem ) ); XGradient aGradient(((const XFillGradientItem&)rFillItemSet.Get(XATTR_FILLGRADIENT)).GetGradientValue()); XHatch aHatch(((const XFillHatchItem&)rFillItemSet.Get(XATTR_FILLHATCH)).GetHatchValue()); sal_Int32 nDX( ((SdrShadowXDistItem&)(rSet.Get(SDRATTR_SHADOWXDIST))).GetValue() ); sal_Int32 nDY( ((SdrShadowYDistItem&)(rSet.Get(SDRATTR_SHADOWYDIST))).GetValue() ); UINT16 nTransp( ((XFillTransparenceItem&) (rSet.Get(XATTR_FILLTRANSPARENCE))).GetValue() ); XFillFloatTransparenceItem aFillFloatTransparence((XFillFloatTransparenceItem&)rSet.Get(XATTR_FILLFLOATTRANSPARENCE)); GDIMetaFile* pMtf=NULL; if( ( eFillStyle != XFILL_NONE ) && ( !aFillFloatTransparence.IsEnabled() ) && ( !nTransp ) ) pMtf=mrXOut.GetOutDev()->GetConnectMetaFile(); if( pMtf != NULL ) { // #104686# Prune non-closed polygons from geometry basegfx::B2DPolyPolygon aPolyPoly; sal_uInt32 i; for( i=0L; iGetMapMode().GetMapUnit() ); Size aStartOffset; Size aBmpOutputSize; // #104609# Call extracted method from XOutputDevice to // determine bitmap size and offset RECT_POINT eRectPoint = (RECT_POINT) ITEMVALUE( rSet, XATTR_FILLBMP_POS, SfxEnumItem ); USHORT nOffX = ITEMVALUE( rSet, XATTR_FILLBMP_TILEOFFSETX, SfxUInt16Item ); USHORT nOffY = ITEMVALUE( rSet, XATTR_FILLBMP_TILEOFFSETY, SfxUInt16Item ); Size aPosOffset( ITEMVALUE( rSet, XATTR_FILLBMP_POSOFFSETX, SfxUInt16Item ), ITEMVALUE( rSet, XATTR_FILLBMP_POSOFFSETY, SfxUInt16Item ) ); BOOL bStretch = ITEMVALUE( rSet, XATTR_FILLBMP_STRETCH, SfxBoolItem ); BOOL bLogSize = ITEMVALUE( rSet, XATTR_FILLBMP_SIZELOG, SfxBoolItem ); Size aSize( labs( ITEMVALUE( rSet, XATTR_FILLBMP_SIZEX, SfxMetricItem ) ), labs( ITEMVALUE( rSet, XATTR_FILLBMP_SIZEY, SfxMetricItem ) ) ); Size aBmpRenderSize; Size aBmpPerCentSize; Size aBmpSizePixel( aBitmap.GetSizePixel() ); if( bLogSize ) aBmpRenderSize = aSize; else aBmpPerCentSize = aSize; ImpCalcBmpFillSizes( aStartOffset, aBmpOutputSize, aPolyRect, aMap, aBitmap, aBmpRenderSize, aBmpPerCentSize, aPosOffset, bLogSize, bTile, bStretch, eRectPoint ); // avoid reimplementation of tiling and offset calculation // -- simply render our texture into a VDev if( bTile && (nOffX || nOffY) ) { // paint texture to VDev, then extract first 2x2 // tiles (to cope with the offset variations) // setup VDev VirtualDevice aVDev; aVDev.SetOutputSizePixel( pOut->LogicToPixel( aPolyRect, aMap ).GetSize() ); aVDev.SetMapMode( aMap ); // setup XOutDev XOutputDevice aXOut( &aVDev ); aXOut.SetFillAttr( rFillItemSet ); // prepare ItemSet to avoid line drawing SfxItemSet aEmptySet( *rFillItemSet.GetPool() ); aEmptySet.Put(XLineStyleItem(XLINE_NONE)); aXOut.SetLineAttr( aEmptySet ); // render into VDev (note: cannot paint smaller // area here, because bitmap size might be // relative to draw rect) Rectangle aOutRect( aPolyRect ); aOutRect.SetPos( Point(0,0) ); aXOut.DrawRect( aOutRect ); // extract first 2x2 tiles Size aTileBmpSize( aBmpOutputSize ); aTileBmpSize.Width() *= 2; aTileBmpSize.Height() *= 2; Size aTileBmpSizePixel( pOut->LogicToPixel( aTileBmpSize ) ); aFillGraphic = Graphic( aVDev.GetBitmap( Point(), aTileBmpSize ) ); aFillGraphic.SetPrefMapMode( MapMode(MAP_PIXEL) ); aFillGraphic.SetPrefSize( aTileBmpSizePixel ); if( aTileBmpSizePixel.Width() == 0 ) aTileBmpSizePixel.Width() = 1; if( aTileBmpSizePixel.Height() == 0 ) aTileBmpSizePixel.Height() = 1; // setup transformation (scale to logical coordinate system. no need for translation) aTransform.matrix[0] *= (double)2*aBmpOutputSize.Width() / aTileBmpSizePixel.Width(); aTransform.matrix[4] *= (double)2*aBmpOutputSize.Height() / aTileBmpSizePixel.Height(); } else { // setup fill graphic aFillGraphic = Graphic( aBitmap ); aFillGraphic.SetPrefMapMode( MapMode(MAP_PIXEL) ); aFillGraphic.SetPrefSize( aBmpSizePixel ); if( aBmpSizePixel.Width() == 0 ) aBmpSizePixel.Width() = 1; if( aBmpSizePixel.Height() == 0 ) aBmpSizePixel.Height() = 1; // setup transformation from size and offset values (scale to logical coordinate system) aTransform.matrix[0] *= (double)aBmpOutputSize.Width() / aBmpSizePixel.Width(); aTransform.matrix[4] *= (double)aBmpOutputSize.Height() / aBmpSizePixel.Height(); // translate aTransform.matrix[2] += aStartOffset.Width(); aTransform.matrix[5] += aStartOffset.Height(); } } } const Color aColorSolid = ((const XFillColorItem&) (rFillItemSet.Get(XATTR_FILLCOLOR))).GetColorValue(); SvtGraphicFill aFill = SvtGraphicFill( PolyPolygon(aPolyPoly), aColorSolid, ITEMVALUE( rFillItemSet, XATTR_FILLTRANSPARENCE, XFillTransparenceItem ) / 100.0, SvtGraphicFill::fillEvenOdd, eType, aTransform, SvtGraphicFill::fillTexture == eType ? bTile : false, eHatch, aHatch.GetColor(), eGrad, aGradient.GetStartColor(), aGradient.GetEndColor(), 0 == aGradient.GetSteps() ? ((int)SvtGraphicFill::gradientStepsInfinite) : aGradient.GetSteps(), // 0 means adaptive/infinite step count aFillGraphic ); #ifdef DBG_UTIL ::rtl::OString aStr( aFill.toString() ); #endif SvMemoryStream aMemStm; aMemStm << aFill; pMtf->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0, static_cast(aMemStm.GetData()), aMemStm.Seek( STREAM_SEEK_TO_END ) ) ); mbCommentWritten = true; } } // #100127# Bracket filled output with a comment, if recording a Mtf ImpGraphicFill::~ImpGraphicFill() { GDIMetaFile* pMtf=NULL; if( mbCommentWritten ) pMtf=mrXOut.GetOutDev()->GetConnectMetaFile(); if( pMtf != NULL ) { pMtf->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_END" ) ); } } /////////////////////////////////////////////////////////////////////////////// // #104609# Extracted from XOutputDevice::ImpCalcBmpFillStartValues void ImpCalcBmpFillSizes( Size& rStartOffset, Size& rBmpOutputSize, const Rectangle& rOutputRect, const MapMode& rOutputMapMode, const Bitmap& rFillBitmap, const Size& rBmpSize, const Size& rBmpPerCent, const Size& rBmpOffPerCent, BOOL bBmpLogSize, BOOL bBmpTile, BOOL bBmpStretch, RECT_POINT eBmpRectPoint ) { BOOL bOriginalSize = FALSE, bScaleSize = FALSE; // Falls keine Groessen gegeben sind ( z.B. alte Dokumente ) // berechnen wir uns die Groesse selber aus der Bitmap // ==> altes Verhalten; // wenn nur eine Groesse gegeben ist, wird die andere // Groesse angepasst berechnet if( bBmpLogSize ) { if( !rBmpSize.Width() && !rBmpSize.Height() ) bOriginalSize = TRUE; else if( !rBmpSize.Width() || !rBmpSize.Height() ) bScaleSize = TRUE; } else { if( !rBmpPerCent.Width() && !rBmpPerCent.Height() ) bOriginalSize = TRUE; else if( !rBmpPerCent.Width() || !rBmpPerCent.Height() ) bScaleSize = TRUE; } // entweder Originalgroesse oder angepasste Groesse if( bOriginalSize || bScaleSize ) { MapMode aBmpPrefMapMode( rFillBitmap.GetPrefMapMode() ); Size aBmpPrefSize( rFillBitmap.GetPrefSize() ); // Falls keine gesetzt ist, nehmen wir Pixel if( !aBmpPrefSize.Width() || !aBmpPrefSize.Height() ) { aBmpPrefSize = rFillBitmap.GetSizePixel(); aBmpPrefMapMode = MAP_PIXEL; } if( bOriginalSize ) { if( MAP_PIXEL == aBmpPrefMapMode.GetMapUnit() ) rBmpOutputSize = Application::GetDefaultDevice()->PixelToLogic( aBmpPrefSize, rOutputMapMode ); else rBmpOutputSize = OutputDevice::LogicToLogic( aBmpPrefSize, aBmpPrefMapMode, rOutputMapMode ); } else { if( bBmpLogSize ) { rBmpOutputSize = rBmpSize; if( !rBmpSize.Width() ) rBmpOutputSize.Width() = FRound( (double) rBmpSize.Height() * aBmpPrefSize.Width() / aBmpPrefSize.Height() ); else rBmpOutputSize.Height() = FRound( (double) rBmpSize.Width() * aBmpPrefSize.Height() / aBmpPrefSize.Width() ); } else { if( !rBmpPerCent.Width() ) { rBmpOutputSize.Height() = FRound( (double) rOutputRect.GetHeight() * rBmpPerCent.Height() / 100. ); rBmpOutputSize.Width() = FRound( (double) rBmpOutputSize.Height() * aBmpPrefSize.Width() / aBmpPrefSize.Height() ); } else { rBmpOutputSize.Width() = FRound( (double) rOutputRect.GetWidth() * rBmpPerCent.Width() / 100. ); rBmpOutputSize.Height() = FRound( (double) rBmpOutputSize.Width() * aBmpPrefSize.Height() / aBmpPrefSize.Width() ); } } } } // ansonsten koennen wir die Groesse leicht selber berechnen else { if( bBmpLogSize ) rBmpOutputSize = rBmpSize; else { rBmpOutputSize.Width() = FRound( (double) rOutputRect.GetWidth() * rBmpPerCent.Width() / 100. ); rBmpOutputSize.Height() = FRound( (double) rOutputRect.GetHeight() * rBmpPerCent.Height() / 100. ); } } // nur bei Kachelung die anderen Positionen berechnen if( bBmpTile ) { Point aStartPoint; // Grundposition der ersten Kachel berechen; // Diese Position wird spaeter zur Berechnung der absoluten // Startposition links oberhalb des Objektes benutzt switch( eBmpRectPoint ) { case( RP_MT ): { aStartPoint.X() = rOutputRect.Left() + ( ( rOutputRect.GetWidth() - rBmpOutputSize.Width() ) >> 1 ); aStartPoint.Y() = rOutputRect.Top(); } break; case( RP_RT ): { aStartPoint.X() = rOutputRect.Right() - rBmpOutputSize.Width(); aStartPoint.Y() = rOutputRect.Top(); } break; case( RP_LM ): { aStartPoint.X() = rOutputRect.Left(); aStartPoint.Y() = rOutputRect.Top() + ( ( rOutputRect.GetHeight() - rBmpOutputSize.Height() ) >> 1 ); } break; case( RP_MM ): { aStartPoint.X() = rOutputRect.Left() + ( ( rOutputRect.GetWidth() - rBmpOutputSize.Width() ) >> 1 ); aStartPoint.Y() = rOutputRect.Top() + ( ( rOutputRect.GetHeight() - rBmpOutputSize.Height() ) >> 1 ); } break; case( RP_RM ): { aStartPoint.X() = rOutputRect.Right() - rBmpOutputSize.Width(); aStartPoint.Y() = rOutputRect.Top() + ( ( rOutputRect.GetHeight() - rBmpOutputSize.Height() ) >> 1 ); } break; case( RP_LB ): { aStartPoint.X() = rOutputRect.Left(); aStartPoint.Y() = rOutputRect.Bottom() - rBmpOutputSize.Height(); } break; case( RP_MB ): { aStartPoint.X() = rOutputRect.Left() + ( ( rOutputRect.GetWidth() - rBmpOutputSize.Width() ) >> 1 ); aStartPoint.Y() = rOutputRect.Bottom() - rBmpOutputSize.Height(); } break; case( RP_RB ): { aStartPoint.X() = rOutputRect.Right() - rBmpOutputSize.Width(); aStartPoint.Y() = rOutputRect.Bottom() - rBmpOutputSize.Height(); } break; // default linke obere Ecke default: aStartPoint = rOutputRect.TopLeft(); break; } // X- oder Y-Positionsoffset beruecksichtigen if( rBmpOffPerCent.Width() ) aStartPoint.X() += ( rBmpOutputSize.Width() * rBmpOffPerCent.Width() / 100 ); if( rBmpOffPerCent.Height() ) aStartPoint.Y() += ( rBmpOutputSize.Height() * rBmpOffPerCent.Height() / 100 ); // echten Startpunkt berechnen ( links oben ) if( rBmpOutputSize.Width() && rBmpOutputSize.Height() ) { const long nDiffX = aStartPoint.X() - rOutputRect.Left(); const long nDiffY = aStartPoint.Y() - rOutputRect.Top(); if ( nDiffX ) { long nCount = nDiffX / rBmpOutputSize.Width() + 1; if ( rBmpOffPerCent.Height() && ( nCount & 1L ) ) nCount++; aStartPoint.X() -= ( nCount * rBmpOutputSize.Width() ); } if ( nDiffY ) { long nCount = nDiffY / rBmpOutputSize.Height() + 1; if ( rBmpOffPerCent.Width() && ( nCount & 1L ) ) nCount++; aStartPoint.Y() -= ( nCount * rBmpOutputSize.Height() ); } } rStartOffset = Size( aStartPoint.X() - rOutputRect.Left(), aStartPoint.Y() - rOutputRect.Top() ); } else { if( bBmpStretch ) { rStartOffset = Size(0, 0); rBmpOutputSize = rOutputRect.GetSize(); } else { rStartOffset = Size( ( rOutputRect.GetWidth() - rBmpOutputSize.Width() ) >> 1, ( rOutputRect.GetHeight() - rBmpOutputSize.Height() ) >> 1 ); } } }