1*25ea7f45SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*25ea7f45SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*25ea7f45SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*25ea7f45SAndrew Rist * distributed with this work for additional information 6*25ea7f45SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*25ea7f45SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*25ea7f45SAndrew Rist * "License"); you may not use this file except in compliance 9*25ea7f45SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*25ea7f45SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*25ea7f45SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*25ea7f45SAndrew Rist * software distributed under the License is distributed on an 15*25ea7f45SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*25ea7f45SAndrew Rist * KIND, either express or implied. See the License for the 17*25ea7f45SAndrew Rist * specific language governing permissions and limitations 18*25ea7f45SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*25ea7f45SAndrew Rist *************************************************************/ 21*25ea7f45SAndrew Rist 22*25ea7f45SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_canvas.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include <canvas/debug.hxx> 28cdf0e10cSrcweir #include <tools/diagnose_ex.h> 29cdf0e10cSrcweir 30cdf0e10cSrcweir #include <rtl/math.hxx> 31cdf0e10cSrcweir 32cdf0e10cSrcweir #include <com/sun/star/rendering/CompositeOperation.hpp> 33cdf0e10cSrcweir #include <com/sun/star/util/Endianness.hpp> 34cdf0e10cSrcweir #include <com/sun/star/rendering/TextDirection.hpp> 35cdf0e10cSrcweir #include <com/sun/star/rendering/TexturingMode.hpp> 36cdf0e10cSrcweir #include <com/sun/star/rendering/PathCapType.hpp> 37cdf0e10cSrcweir #include <com/sun/star/rendering/PathJoinType.hpp> 38cdf0e10cSrcweir 39cdf0e10cSrcweir #include <tools/poly.hxx> 40cdf0e10cSrcweir #include <vcl/window.hxx> 41cdf0e10cSrcweir #include <vcl/bitmapex.hxx> 42cdf0e10cSrcweir #include <vcl/bmpacc.hxx> 43cdf0e10cSrcweir #include <vcl/canvastools.hxx> 44cdf0e10cSrcweir 45cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 46cdf0e10cSrcweir #include <basegfx/range/b2drectangle.hxx> 47cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx> 48cdf0e10cSrcweir #include <basegfx/vector/b2dsize.hxx> 49cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx> 50cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 51cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx> 52cdf0e10cSrcweir #include <basegfx/polygon/b2dlinegeometry.hxx> 53cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx> 54cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 55cdf0e10cSrcweir 56cdf0e10cSrcweir #include <utility> 57cdf0e10cSrcweir 58cdf0e10cSrcweir #include <comphelper/sequence.hxx> 59cdf0e10cSrcweir #include <canvas/canvastools.hxx> 60cdf0e10cSrcweir 61cdf0e10cSrcweir #include "textlayout.hxx" 62cdf0e10cSrcweir #include "canvashelper.hxx" 63cdf0e10cSrcweir #include "canvasbitmap.hxx" 64cdf0e10cSrcweir #include "impltools.hxx" 65cdf0e10cSrcweir #include "canvasfont.hxx" 66cdf0e10cSrcweir 67cdf0e10cSrcweir 68cdf0e10cSrcweir using namespace ::com::sun::star; 69cdf0e10cSrcweir 70cdf0e10cSrcweir namespace vclcanvas 71cdf0e10cSrcweir { 72cdf0e10cSrcweir namespace 73cdf0e10cSrcweir { 74cdf0e10cSrcweir basegfx::B2DLineJoin b2DJoineFromJoin( sal_Int8 nJoinType ) 75cdf0e10cSrcweir { 76cdf0e10cSrcweir switch( nJoinType ) 77cdf0e10cSrcweir { 78cdf0e10cSrcweir case rendering::PathJoinType::NONE: 79cdf0e10cSrcweir return basegfx::B2DLINEJOIN_NONE; 80cdf0e10cSrcweir 81cdf0e10cSrcweir case rendering::PathJoinType::MITER: 82cdf0e10cSrcweir return basegfx::B2DLINEJOIN_MITER; 83cdf0e10cSrcweir 84cdf0e10cSrcweir case rendering::PathJoinType::ROUND: 85cdf0e10cSrcweir return basegfx::B2DLINEJOIN_ROUND; 86cdf0e10cSrcweir 87cdf0e10cSrcweir case rendering::PathJoinType::BEVEL: 88cdf0e10cSrcweir return basegfx::B2DLINEJOIN_BEVEL; 89cdf0e10cSrcweir 90cdf0e10cSrcweir default: 91cdf0e10cSrcweir ENSURE_OR_THROW( false, 92cdf0e10cSrcweir "b2DJoineFromJoin(): Unexpected join type" ); 93cdf0e10cSrcweir } 94cdf0e10cSrcweir 95cdf0e10cSrcweir return basegfx::B2DLINEJOIN_NONE; 96cdf0e10cSrcweir } 97cdf0e10cSrcweir } 98cdf0e10cSrcweir 99cdf0e10cSrcweir CanvasHelper::CanvasHelper() : 100cdf0e10cSrcweir mpDevice(), 101cdf0e10cSrcweir mpProtectedOutDev(), 102cdf0e10cSrcweir mpOutDev(), 103cdf0e10cSrcweir mp2ndOutDev(), 104cdf0e10cSrcweir mbHaveAlpha( false ) 105cdf0e10cSrcweir { 106cdf0e10cSrcweir } 107cdf0e10cSrcweir 108cdf0e10cSrcweir void CanvasHelper::disposing() 109cdf0e10cSrcweir { 110cdf0e10cSrcweir mpDevice = NULL; 111cdf0e10cSrcweir mpProtectedOutDev.reset(); 112cdf0e10cSrcweir mpOutDev.reset(); 113cdf0e10cSrcweir mp2ndOutDev.reset(); 114cdf0e10cSrcweir } 115cdf0e10cSrcweir 116cdf0e10cSrcweir void CanvasHelper::init( rendering::XGraphicDevice& rDevice, 117cdf0e10cSrcweir const OutDevProviderSharedPtr& rOutDev, 118cdf0e10cSrcweir bool bProtect, 119cdf0e10cSrcweir bool bHaveAlpha ) 120cdf0e10cSrcweir { 121cdf0e10cSrcweir // cast away const, need to change refcount (as this is 122cdf0e10cSrcweir // ~invisible to client code, still logically const) 123cdf0e10cSrcweir mpDevice = &rDevice; 124cdf0e10cSrcweir mbHaveAlpha = bHaveAlpha; 125cdf0e10cSrcweir 126cdf0e10cSrcweir setOutDev( rOutDev, bProtect ); 127cdf0e10cSrcweir } 128cdf0e10cSrcweir 129cdf0e10cSrcweir void CanvasHelper::setOutDev( const OutDevProviderSharedPtr& rOutDev, 130cdf0e10cSrcweir bool bProtect ) 131cdf0e10cSrcweir { 132cdf0e10cSrcweir if( bProtect ) 133cdf0e10cSrcweir mpProtectedOutDev = rOutDev; 134cdf0e10cSrcweir else 135cdf0e10cSrcweir mpProtectedOutDev.reset(); 136cdf0e10cSrcweir 137cdf0e10cSrcweir mpOutDev = rOutDev; 138cdf0e10cSrcweir } 139cdf0e10cSrcweir 140cdf0e10cSrcweir void CanvasHelper::setBackgroundOutDev( const OutDevProviderSharedPtr& rOutDev ) 141cdf0e10cSrcweir { 142cdf0e10cSrcweir mp2ndOutDev = rOutDev; 143cdf0e10cSrcweir mp2ndOutDev->getOutDev().EnableMapMode( sal_False ); 144cdf0e10cSrcweir } 145cdf0e10cSrcweir 146cdf0e10cSrcweir void CanvasHelper::clear() 147cdf0e10cSrcweir { 148cdf0e10cSrcweir // are we disposed? 149cdf0e10cSrcweir if( mpOutDev ) 150cdf0e10cSrcweir { 151cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 152cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 153cdf0e10cSrcweir 154cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 155cdf0e10cSrcweir rOutDev.SetLineColor( COL_WHITE ); 156cdf0e10cSrcweir rOutDev.SetFillColor( COL_WHITE ); 157cdf0e10cSrcweir rOutDev.DrawRect( Rectangle( Point(), 158cdf0e10cSrcweir rOutDev.GetOutputSizePixel()) ); 159cdf0e10cSrcweir 160cdf0e10cSrcweir if( mp2ndOutDev ) 161cdf0e10cSrcweir { 162cdf0e10cSrcweir OutputDevice& rOutDev2( mp2ndOutDev->getOutDev() ); 163cdf0e10cSrcweir 164cdf0e10cSrcweir rOutDev2.SetDrawMode( DRAWMODE_DEFAULT ); 165cdf0e10cSrcweir rOutDev2.EnableMapMode( sal_False ); 166cdf0e10cSrcweir rOutDev2.SetLineColor( COL_WHITE ); 167cdf0e10cSrcweir rOutDev2.SetFillColor( COL_WHITE ); 168cdf0e10cSrcweir rOutDev2.DrawRect( Rectangle( Point(), 169cdf0e10cSrcweir rOutDev2.GetOutputSizePixel()) ); 170cdf0e10cSrcweir rOutDev2.SetDrawMode( DRAWMODE_BLACKLINE | DRAWMODE_BLACKFILL | DRAWMODE_BLACKTEXT | 171cdf0e10cSrcweir DRAWMODE_BLACKGRADIENT | DRAWMODE_BLACKBITMAP ); 172cdf0e10cSrcweir } 173cdf0e10cSrcweir } 174cdf0e10cSrcweir } 175cdf0e10cSrcweir 176cdf0e10cSrcweir void CanvasHelper::drawPoint( const rendering::XCanvas* , 177cdf0e10cSrcweir const geometry::RealPoint2D& aPoint, 178cdf0e10cSrcweir const rendering::ViewState& viewState, 179cdf0e10cSrcweir const rendering::RenderState& renderState ) 180cdf0e10cSrcweir { 181cdf0e10cSrcweir // are we disposed? 182cdf0e10cSrcweir if( mpOutDev ) 183cdf0e10cSrcweir { 184cdf0e10cSrcweir // nope, render 185cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 186cdf0e10cSrcweir setupOutDevState( viewState, renderState, LINE_COLOR ); 187cdf0e10cSrcweir 188cdf0e10cSrcweir const Point aOutPoint( tools::mapRealPoint2D( aPoint, 189cdf0e10cSrcweir viewState, renderState ) ); 190cdf0e10cSrcweir // TODO(F1): alpha 191cdf0e10cSrcweir mpOutDev->getOutDev().DrawPixel( aOutPoint ); 192cdf0e10cSrcweir 193cdf0e10cSrcweir if( mp2ndOutDev ) 194cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPixel( aOutPoint ); 195cdf0e10cSrcweir } 196cdf0e10cSrcweir } 197cdf0e10cSrcweir 198cdf0e10cSrcweir void CanvasHelper::drawLine( const rendering::XCanvas* , 199cdf0e10cSrcweir const geometry::RealPoint2D& aStartRealPoint2D, 200cdf0e10cSrcweir const geometry::RealPoint2D& aEndRealPoint2D, 201cdf0e10cSrcweir const rendering::ViewState& viewState, 202cdf0e10cSrcweir const rendering::RenderState& renderState ) 203cdf0e10cSrcweir { 204cdf0e10cSrcweir // are we disposed? 205cdf0e10cSrcweir if( mpOutDev ) 206cdf0e10cSrcweir { 207cdf0e10cSrcweir // nope, render 208cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 209cdf0e10cSrcweir setupOutDevState( viewState, renderState, LINE_COLOR ); 210cdf0e10cSrcweir 211cdf0e10cSrcweir const Point aStartPoint( tools::mapRealPoint2D( aStartRealPoint2D, 212cdf0e10cSrcweir viewState, renderState ) ); 213cdf0e10cSrcweir const Point aEndPoint( tools::mapRealPoint2D( aEndRealPoint2D, 214cdf0e10cSrcweir viewState, renderState ) ); 215cdf0e10cSrcweir // TODO(F2): alpha 216cdf0e10cSrcweir mpOutDev->getOutDev().DrawLine( aStartPoint, aEndPoint ); 217cdf0e10cSrcweir 218cdf0e10cSrcweir if( mp2ndOutDev ) 219cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawLine( aStartPoint, aEndPoint ); 220cdf0e10cSrcweir } 221cdf0e10cSrcweir } 222cdf0e10cSrcweir 223cdf0e10cSrcweir void CanvasHelper::drawBezier( const rendering::XCanvas* , 224cdf0e10cSrcweir const geometry::RealBezierSegment2D& aBezierSegment, 225cdf0e10cSrcweir const geometry::RealPoint2D& _aEndPoint, 226cdf0e10cSrcweir const rendering::ViewState& viewState, 227cdf0e10cSrcweir const rendering::RenderState& renderState ) 228cdf0e10cSrcweir { 229cdf0e10cSrcweir if( mpOutDev ) 230cdf0e10cSrcweir { 231cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 232cdf0e10cSrcweir setupOutDevState( viewState, renderState, LINE_COLOR ); 233cdf0e10cSrcweir 234cdf0e10cSrcweir const Point& rStartPoint( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.Px, 235cdf0e10cSrcweir aBezierSegment.Py), 236cdf0e10cSrcweir viewState, renderState ) ); 237cdf0e10cSrcweir const Point& rCtrlPoint1( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C1x, 238cdf0e10cSrcweir aBezierSegment.C1y), 239cdf0e10cSrcweir viewState, renderState ) ); 240cdf0e10cSrcweir const Point& rCtrlPoint2( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C2x, 241cdf0e10cSrcweir aBezierSegment.C2y), 242cdf0e10cSrcweir viewState, renderState ) ); 243cdf0e10cSrcweir const Point& rEndPoint( tools::mapRealPoint2D( _aEndPoint, 244cdf0e10cSrcweir viewState, renderState ) ); 245cdf0e10cSrcweir 246cdf0e10cSrcweir ::Polygon aPoly(4); 247cdf0e10cSrcweir aPoly.SetPoint( rStartPoint, 0 ); 248cdf0e10cSrcweir aPoly.SetFlags( 0, POLY_NORMAL ); 249cdf0e10cSrcweir aPoly.SetPoint( rCtrlPoint1, 1 ); 250cdf0e10cSrcweir aPoly.SetFlags( 1, POLY_CONTROL ); 251cdf0e10cSrcweir aPoly.SetPoint( rCtrlPoint2, 2 ); 252cdf0e10cSrcweir aPoly.SetFlags( 2, POLY_CONTROL ); 253cdf0e10cSrcweir aPoly.SetPoint( rEndPoint, 3 ); 254cdf0e10cSrcweir aPoly.SetFlags( 3, POLY_NORMAL ); 255cdf0e10cSrcweir 256cdf0e10cSrcweir // TODO(F2): alpha 257cdf0e10cSrcweir mpOutDev->getOutDev().DrawPolygon( aPoly ); 258cdf0e10cSrcweir if( mp2ndOutDev ) 259cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolygon( aPoly ); 260cdf0e10cSrcweir } 261cdf0e10cSrcweir } 262cdf0e10cSrcweir 263cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* , 264cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, 265cdf0e10cSrcweir const rendering::ViewState& viewState, 266cdf0e10cSrcweir const rendering::RenderState& renderState ) 267cdf0e10cSrcweir { 268cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xPolyPolygon.is(), 269cdf0e10cSrcweir "polygon is NULL"); 270cdf0e10cSrcweir 271cdf0e10cSrcweir if( mpOutDev ) 272cdf0e10cSrcweir { 273cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 274cdf0e10cSrcweir setupOutDevState( viewState, renderState, LINE_COLOR ); 275cdf0e10cSrcweir 276cdf0e10cSrcweir const ::basegfx::B2DPolyPolygon& rPolyPoly( 277cdf0e10cSrcweir ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon) ); 278cdf0e10cSrcweir const PolyPolygon aPolyPoly( tools::mapPolyPolygon( rPolyPoly, viewState, renderState ) ); 279cdf0e10cSrcweir 280cdf0e10cSrcweir if( rPolyPoly.isClosed() ) 281cdf0e10cSrcweir { 282cdf0e10cSrcweir mpOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); 283cdf0e10cSrcweir 284cdf0e10cSrcweir if( mp2ndOutDev ) 285cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); 286cdf0e10cSrcweir } 287cdf0e10cSrcweir else 288cdf0e10cSrcweir { 289cdf0e10cSrcweir // mixed open/closed state. Cannot render open polygon 290cdf0e10cSrcweir // via DrawPolyPolygon(), since that implicitley 291cdf0e10cSrcweir // closed every polygon. OTOH, no need to distinguish 292cdf0e10cSrcweir // further and render closed polygons via 293cdf0e10cSrcweir // DrawPolygon(), and open ones via DrawPolyLine(): 294cdf0e10cSrcweir // closed polygons will simply already contain the 295cdf0e10cSrcweir // closing segment. 296cdf0e10cSrcweir sal_uInt16 nSize( aPolyPoly.Count() ); 297cdf0e10cSrcweir 298cdf0e10cSrcweir for( sal_uInt16 i=0; i<nSize; ++i ) 299cdf0e10cSrcweir { 300cdf0e10cSrcweir mpOutDev->getOutDev().DrawPolyLine( aPolyPoly[i] ); 301cdf0e10cSrcweir 302cdf0e10cSrcweir if( mp2ndOutDev ) 303cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolyLine( aPolyPoly[i] ); 304cdf0e10cSrcweir } 305cdf0e10cSrcweir } 306cdf0e10cSrcweir } 307cdf0e10cSrcweir 308cdf0e10cSrcweir // TODO(P1): Provide caching here. 309cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 310cdf0e10cSrcweir } 311cdf0e10cSrcweir 312cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* , 313cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, 314cdf0e10cSrcweir const rendering::ViewState& viewState, 315cdf0e10cSrcweir const rendering::RenderState& renderState, 316cdf0e10cSrcweir const rendering::StrokeAttributes& strokeAttributes ) 317cdf0e10cSrcweir { 318cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xPolyPolygon.is(), 319cdf0e10cSrcweir "polygon is NULL"); 320cdf0e10cSrcweir 321cdf0e10cSrcweir if( mpOutDev ) 322cdf0e10cSrcweir { 323cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 324cdf0e10cSrcweir 325cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 326cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform(aMatrix, viewState, renderState); 327cdf0e10cSrcweir 328cdf0e10cSrcweir ::basegfx::B2DSize aLinePixelSize(strokeAttributes.StrokeWidth, 329cdf0e10cSrcweir strokeAttributes.StrokeWidth); 330cdf0e10cSrcweir aLinePixelSize *= aMatrix; 331cdf0e10cSrcweir 332cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aPolyPoly( 333cdf0e10cSrcweir ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon) ); 334cdf0e10cSrcweir 335cdf0e10cSrcweir if( aPolyPoly.areControlPointsUsed() ) 336cdf0e10cSrcweir { 337cdf0e10cSrcweir // AW: Not needed for ApplyLineDashing anymore; should be removed 338cdf0e10cSrcweir aPolyPoly = ::basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly); 339cdf0e10cSrcweir } 340cdf0e10cSrcweir 341cdf0e10cSrcweir // apply dashing, if any 342cdf0e10cSrcweir if( strokeAttributes.DashArray.getLength() ) 343cdf0e10cSrcweir { 344cdf0e10cSrcweir const ::std::vector<double>& aDashArray( 345cdf0e10cSrcweir ::comphelper::sequenceToContainer< ::std::vector<double> >(strokeAttributes.DashArray) ); 346cdf0e10cSrcweir 347cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aDashedPolyPoly; 348cdf0e10cSrcweir 349cdf0e10cSrcweir for( sal_uInt32 i=0; i<aPolyPoly.count(); ++i ) 350cdf0e10cSrcweir { 351cdf0e10cSrcweir // AW: new interface; You may also get gaps in the same run now 352cdf0e10cSrcweir basegfx::tools::applyLineDashing(aPolyPoly.getB2DPolygon(i), aDashArray, &aDashedPolyPoly); 353cdf0e10cSrcweir //aDashedPolyPoly.append( 354cdf0e10cSrcweir // ::basegfx::tools::applyLineDashing( aPolyPoly.getB2DPolygon(i), 355cdf0e10cSrcweir // aDashArray ) ); 356cdf0e10cSrcweir } 357cdf0e10cSrcweir 358cdf0e10cSrcweir aPolyPoly = aDashedPolyPoly; 359cdf0e10cSrcweir } 360cdf0e10cSrcweir 361cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aStrokedPolyPoly; 362cdf0e10cSrcweir if( aLinePixelSize.getLength() < 1.42 ) 363cdf0e10cSrcweir { 364cdf0e10cSrcweir // line width < 1.0 in device pixel, thus, output as a 365cdf0e10cSrcweir // simple hairline poly-polygon 366cdf0e10cSrcweir setupOutDevState( viewState, renderState, LINE_COLOR ); 367cdf0e10cSrcweir 368cdf0e10cSrcweir aStrokedPolyPoly = aPolyPoly; 369cdf0e10cSrcweir } 370cdf0e10cSrcweir else 371cdf0e10cSrcweir { 372cdf0e10cSrcweir // render as a 'thick' line 373cdf0e10cSrcweir setupOutDevState( viewState, renderState, FILL_COLOR ); 374cdf0e10cSrcweir 375cdf0e10cSrcweir for( sal_uInt32 i=0; i<aPolyPoly.count(); ++i ) 376cdf0e10cSrcweir { 377cdf0e10cSrcweir // TODO(F2): Use MiterLimit from StrokeAttributes, 378cdf0e10cSrcweir // need to convert it here to angle. 379cdf0e10cSrcweir 380cdf0e10cSrcweir // TODO(F2): Also use Cap settings from 381cdf0e10cSrcweir // StrokeAttributes, the 382cdf0e10cSrcweir // createAreaGeometryForLineStartEnd() method does not 383cdf0e10cSrcweir // seem to fit very well here 384cdf0e10cSrcweir 385cdf0e10cSrcweir // AW: New interface, will create bezier polygons now 386cdf0e10cSrcweir aStrokedPolyPoly.append(basegfx::tools::createAreaGeometry( 387cdf0e10cSrcweir aPolyPoly.getB2DPolygon(i), strokeAttributes.StrokeWidth*0.5, b2DJoineFromJoin(strokeAttributes.JoinType))); 388cdf0e10cSrcweir //aStrokedPolyPoly.append( 389cdf0e10cSrcweir // ::basegfx::tools::createAreaGeometryForPolygon( aPolyPoly.getB2DPolygon(i), 390cdf0e10cSrcweir // strokeAttributes.StrokeWidth*0.5, 391cdf0e10cSrcweir // b2DJoineFromJoin(strokeAttributes.JoinType) ) ); 392cdf0e10cSrcweir } 393cdf0e10cSrcweir } 394cdf0e10cSrcweir 395cdf0e10cSrcweir // transform only _now_, all the StrokeAttributes are in 396cdf0e10cSrcweir // user coordinates. 397cdf0e10cSrcweir aStrokedPolyPoly.transform( aMatrix ); 398cdf0e10cSrcweir 399cdf0e10cSrcweir const PolyPolygon aVCLPolyPoly( aStrokedPolyPoly ); 400cdf0e10cSrcweir 401cdf0e10cSrcweir // TODO(F2): When using alpha here, must handle that via 402cdf0e10cSrcweir // temporary surface or somesuch. 403cdf0e10cSrcweir 404cdf0e10cSrcweir // Note: the generated stroke poly-polygon is NOT free of 405cdf0e10cSrcweir // self-intersections. Therefore, if we would render it 406cdf0e10cSrcweir // via OutDev::DrawPolyPolygon(), on/off fill would 407cdf0e10cSrcweir // generate off areas on those self-intersections. 408cdf0e10cSrcweir sal_uInt16 nSize( aVCLPolyPoly.Count() ); 409cdf0e10cSrcweir 410cdf0e10cSrcweir for( sal_uInt16 i=0; i<nSize; ++i ) 411cdf0e10cSrcweir { 412cdf0e10cSrcweir if( aStrokedPolyPoly.getB2DPolygon( i ).isClosed() ) { 413cdf0e10cSrcweir mpOutDev->getOutDev().DrawPolygon( aVCLPolyPoly[i] ); 414cdf0e10cSrcweir if( mp2ndOutDev ) 415cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolygon( aVCLPolyPoly[i] ); 416cdf0e10cSrcweir } else { 417cdf0e10cSrcweir const sal_uInt16 nPolySize = aVCLPolyPoly[i].GetSize(); 418cdf0e10cSrcweir if( nPolySize ) { 419cdf0e10cSrcweir Point rPrevPoint = aVCLPolyPoly[i].GetPoint( 0 ); 420cdf0e10cSrcweir Point rPoint; 421cdf0e10cSrcweir 422cdf0e10cSrcweir for( sal_uInt16 j=1; j<nPolySize; j++ ) { 423cdf0e10cSrcweir rPoint = aVCLPolyPoly[i].GetPoint( j ); 424cdf0e10cSrcweir mpOutDev->getOutDev().DrawLine( rPrevPoint, rPoint ); 425cdf0e10cSrcweir if( mp2ndOutDev ) 426cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawLine( rPrevPoint, rPoint ); 427cdf0e10cSrcweir rPrevPoint = rPoint; 428cdf0e10cSrcweir } 429cdf0e10cSrcweir } 430cdf0e10cSrcweir } 431cdf0e10cSrcweir } 432cdf0e10cSrcweir } 433cdf0e10cSrcweir 434cdf0e10cSrcweir // TODO(P1): Provide caching here. 435cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 436cdf0e10cSrcweir } 437cdf0e10cSrcweir 438cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas* , 439cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& , 440cdf0e10cSrcweir const rendering::ViewState& , 441cdf0e10cSrcweir const rendering::RenderState& , 442cdf0e10cSrcweir const uno::Sequence< rendering::Texture >& , 443cdf0e10cSrcweir const rendering::StrokeAttributes& ) 444cdf0e10cSrcweir { 445cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 446cdf0e10cSrcweir } 447cdf0e10cSrcweir 448cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas* , 449cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& , 450cdf0e10cSrcweir const rendering::ViewState& , 451cdf0e10cSrcweir const rendering::RenderState& , 452cdf0e10cSrcweir const uno::Sequence< rendering::Texture >& , 453cdf0e10cSrcweir const uno::Reference< geometry::XMapping2D >& , 454cdf0e10cSrcweir const rendering::StrokeAttributes& ) 455cdf0e10cSrcweir { 456cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 457cdf0e10cSrcweir } 458cdf0e10cSrcweir 459cdf0e10cSrcweir uno::Reference< rendering::XPolyPolygon2D > CanvasHelper::queryStrokeShapes( const rendering::XCanvas* , 460cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& , 461cdf0e10cSrcweir const rendering::ViewState& , 462cdf0e10cSrcweir const rendering::RenderState& , 463cdf0e10cSrcweir const rendering::StrokeAttributes& ) 464cdf0e10cSrcweir { 465cdf0e10cSrcweir return uno::Reference< rendering::XPolyPolygon2D >(NULL); 466cdf0e10cSrcweir } 467cdf0e10cSrcweir 468cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillPolyPolygon( const rendering::XCanvas* , 469cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, 470cdf0e10cSrcweir const rendering::ViewState& viewState, 471cdf0e10cSrcweir const rendering::RenderState& renderState ) 472cdf0e10cSrcweir { 473cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xPolyPolygon.is(), 474cdf0e10cSrcweir "polygon is NULL"); 475cdf0e10cSrcweir 476cdf0e10cSrcweir if( mpOutDev ) 477cdf0e10cSrcweir { 478cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 479cdf0e10cSrcweir 480cdf0e10cSrcweir const int nTransparency( setupOutDevState( viewState, renderState, FILL_COLOR ) ); 481cdf0e10cSrcweir const int nTransPercent( (nTransparency * 100 + 128) / 255 ); // normal rounding, no truncation here 482cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aB2DPolyPoly( 483cdf0e10cSrcweir ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon)); 484cdf0e10cSrcweir aB2DPolyPoly.setClosed(true); // ensure closed poly, otherwise VCL does not fill 485cdf0e10cSrcweir const PolyPolygon aPolyPoly( tools::mapPolyPolygon( 486cdf0e10cSrcweir aB2DPolyPoly, 487cdf0e10cSrcweir viewState, renderState ) ); 488cdf0e10cSrcweir const bool bSourceAlpha( renderState.CompositeOperation == rendering::CompositeOperation::SOURCE ); 489cdf0e10cSrcweir if( !nTransparency || bSourceAlpha ) 490cdf0e10cSrcweir { 491cdf0e10cSrcweir mpOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); 492cdf0e10cSrcweir } 493cdf0e10cSrcweir else 494cdf0e10cSrcweir { 495cdf0e10cSrcweir mpOutDev->getOutDev().DrawTransparent( aPolyPoly, (sal_uInt16)nTransPercent ); 496cdf0e10cSrcweir } 497cdf0e10cSrcweir 498cdf0e10cSrcweir if( mp2ndOutDev ) 499cdf0e10cSrcweir { 500cdf0e10cSrcweir if( !nTransparency || bSourceAlpha ) 501cdf0e10cSrcweir { 502cdf0e10cSrcweir // HACK. Normally, CanvasHelper does not care 503cdf0e10cSrcweir // about actually what mp2ndOutDev is... 504cdf0e10cSrcweir if( bSourceAlpha && nTransparency == 255 ) 505cdf0e10cSrcweir { 506cdf0e10cSrcweir mp2ndOutDev->getOutDev().SetDrawMode( DRAWMODE_WHITELINE | DRAWMODE_WHITEFILL | DRAWMODE_WHITETEXT | 507cdf0e10cSrcweir DRAWMODE_WHITEGRADIENT | DRAWMODE_WHITEBITMAP ); 508cdf0e10cSrcweir mp2ndOutDev->getOutDev().SetFillColor( COL_WHITE ); 509cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); 510cdf0e10cSrcweir mp2ndOutDev->getOutDev().SetDrawMode( DRAWMODE_BLACKLINE | DRAWMODE_BLACKFILL | DRAWMODE_BLACKTEXT | 511cdf0e10cSrcweir DRAWMODE_BLACKGRADIENT | DRAWMODE_BLACKBITMAP ); 512cdf0e10cSrcweir } 513cdf0e10cSrcweir else 514cdf0e10cSrcweir { 515cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); 516cdf0e10cSrcweir } 517cdf0e10cSrcweir } 518cdf0e10cSrcweir else 519cdf0e10cSrcweir { 520cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawTransparent( aPolyPoly, (sal_uInt16)nTransPercent ); 521cdf0e10cSrcweir } 522cdf0e10cSrcweir } 523cdf0e10cSrcweir } 524cdf0e10cSrcweir 525cdf0e10cSrcweir // TODO(P1): Provide caching here. 526cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 527cdf0e10cSrcweir } 528cdf0e10cSrcweir 529cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* , 530cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& , 531cdf0e10cSrcweir const rendering::ViewState& , 532cdf0e10cSrcweir const rendering::RenderState& , 533cdf0e10cSrcweir const uno::Sequence< rendering::Texture >& , 534cdf0e10cSrcweir const uno::Reference< geometry::XMapping2D >& ) 535cdf0e10cSrcweir { 536cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 537cdf0e10cSrcweir } 538cdf0e10cSrcweir 539cdf0e10cSrcweir uno::Reference< rendering::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* , 540cdf0e10cSrcweir const rendering::FontRequest& fontRequest, 541cdf0e10cSrcweir const uno::Sequence< beans::PropertyValue >& extraFontProperties, 542cdf0e10cSrcweir const geometry::Matrix2D& fontMatrix ) 543cdf0e10cSrcweir { 544cdf0e10cSrcweir if( mpOutDev && mpDevice ) 545cdf0e10cSrcweir { 546cdf0e10cSrcweir // TODO(F2): font properties and font matrix 547cdf0e10cSrcweir return uno::Reference< rendering::XCanvasFont >( 548cdf0e10cSrcweir new CanvasFont(fontRequest, extraFontProperties, fontMatrix, 549cdf0e10cSrcweir *mpDevice, mpOutDev) ); 550cdf0e10cSrcweir } 551cdf0e10cSrcweir 552cdf0e10cSrcweir return uno::Reference< rendering::XCanvasFont >(); 553cdf0e10cSrcweir } 554cdf0e10cSrcweir 555cdf0e10cSrcweir uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* , 556cdf0e10cSrcweir const rendering::FontInfo& , 557cdf0e10cSrcweir const uno::Sequence< beans::PropertyValue >& ) 558cdf0e10cSrcweir { 559cdf0e10cSrcweir // TODO(F2) 560cdf0e10cSrcweir return uno::Sequence< rendering::FontInfo >(); 561cdf0e10cSrcweir } 562cdf0e10cSrcweir 563cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* , 564cdf0e10cSrcweir const rendering::StringContext& text, 565cdf0e10cSrcweir const uno::Reference< rendering::XCanvasFont >& xFont, 566cdf0e10cSrcweir const rendering::ViewState& viewState, 567cdf0e10cSrcweir const rendering::RenderState& renderState, 568cdf0e10cSrcweir sal_Int8 textDirection ) 569cdf0e10cSrcweir { 570cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xFont.is(), 571cdf0e10cSrcweir "font is NULL"); 572cdf0e10cSrcweir 573cdf0e10cSrcweir if( mpOutDev ) 574cdf0e10cSrcweir { 575cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 576cdf0e10cSrcweir 577cdf0e10cSrcweir ::Point aOutpos; 578cdf0e10cSrcweir if( !setupTextOutput( aOutpos, viewState, renderState, xFont ) ) 579cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); // no output necessary 580cdf0e10cSrcweir 581cdf0e10cSrcweir // change text direction and layout mode 582cdf0e10cSrcweir sal_uIntPtr nLayoutMode(0); 583cdf0e10cSrcweir switch( textDirection ) 584cdf0e10cSrcweir { 585cdf0e10cSrcweir case rendering::TextDirection::WEAK_LEFT_TO_RIGHT: 586cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_BIDI_LTR; 587cdf0e10cSrcweir // FALLTHROUGH intended 588cdf0e10cSrcweir case rendering::TextDirection::STRONG_LEFT_TO_RIGHT: 589cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG; 590cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_TEXTORIGIN_LEFT; 591cdf0e10cSrcweir break; 592cdf0e10cSrcweir 593cdf0e10cSrcweir case rendering::TextDirection::WEAK_RIGHT_TO_LEFT: 594cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_BIDI_RTL; 595cdf0e10cSrcweir // FALLTHROUGH intended 596cdf0e10cSrcweir case rendering::TextDirection::STRONG_RIGHT_TO_LEFT: 597cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG; 598cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_TEXTORIGIN_RIGHT; 599cdf0e10cSrcweir break; 600cdf0e10cSrcweir } 601cdf0e10cSrcweir 602cdf0e10cSrcweir // TODO(F2): alpha 603cdf0e10cSrcweir mpOutDev->getOutDev().SetLayoutMode( nLayoutMode ); 604cdf0e10cSrcweir mpOutDev->getOutDev().DrawText( aOutpos, 605cdf0e10cSrcweir text.Text, 606cdf0e10cSrcweir ::canvas::tools::numeric_cast<sal_uInt16>(text.StartPosition), 607cdf0e10cSrcweir ::canvas::tools::numeric_cast<sal_uInt16>(text.Length) ); 608cdf0e10cSrcweir 609cdf0e10cSrcweir if( mp2ndOutDev ) 610cdf0e10cSrcweir { 611cdf0e10cSrcweir mp2ndOutDev->getOutDev().SetLayoutMode( nLayoutMode ); 612cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawText( aOutpos, 613cdf0e10cSrcweir text.Text, 614cdf0e10cSrcweir ::canvas::tools::numeric_cast<sal_uInt16>(text.StartPosition), 615cdf0e10cSrcweir ::canvas::tools::numeric_cast<sal_uInt16>(text.Length) ); 616cdf0e10cSrcweir } 617cdf0e10cSrcweir } 618cdf0e10cSrcweir 619cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 620cdf0e10cSrcweir } 621cdf0e10cSrcweir 622cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* , 623cdf0e10cSrcweir const uno::Reference< rendering::XTextLayout >& xLayoutedText, 624cdf0e10cSrcweir const rendering::ViewState& viewState, 625cdf0e10cSrcweir const rendering::RenderState& renderState ) 626cdf0e10cSrcweir { 627cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xLayoutedText.is(), 628cdf0e10cSrcweir "layout is NULL"); 629cdf0e10cSrcweir 630cdf0e10cSrcweir TextLayout* pTextLayout = dynamic_cast< TextLayout* >( xLayoutedText.get() ); 631cdf0e10cSrcweir 632cdf0e10cSrcweir if( pTextLayout ) 633cdf0e10cSrcweir { 634cdf0e10cSrcweir if( mpOutDev ) 635cdf0e10cSrcweir { 636cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 637cdf0e10cSrcweir 638cdf0e10cSrcweir // TODO(T3): Race condition. We're taking the font 639cdf0e10cSrcweir // from xLayoutedText, and then calling draw() at it, 640cdf0e10cSrcweir // without exclusive access. Move setupTextOutput(), 641cdf0e10cSrcweir // e.g. to impltools? 642cdf0e10cSrcweir 643cdf0e10cSrcweir ::Point aOutpos; 644cdf0e10cSrcweir if( !setupTextOutput( aOutpos, viewState, renderState, xLayoutedText->getFont() ) ) 645cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); // no output necessary 646cdf0e10cSrcweir 647cdf0e10cSrcweir // TODO(F2): What about the offset scalings? 648cdf0e10cSrcweir // TODO(F2): alpha 649cdf0e10cSrcweir pTextLayout->draw( mpOutDev->getOutDev(), aOutpos, viewState, renderState ); 650cdf0e10cSrcweir 651cdf0e10cSrcweir if( mp2ndOutDev ) 652cdf0e10cSrcweir pTextLayout->draw( mp2ndOutDev->getOutDev(), aOutpos, viewState, renderState ); 653cdf0e10cSrcweir } 654cdf0e10cSrcweir } 655cdf0e10cSrcweir else 656cdf0e10cSrcweir { 657cdf0e10cSrcweir ENSURE_ARG_OR_THROW( false, 658cdf0e10cSrcweir "TextLayout not compatible with this canvas" ); 659cdf0e10cSrcweir } 660cdf0e10cSrcweir 661cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 662cdf0e10cSrcweir } 663cdf0e10cSrcweir 664cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::implDrawBitmap( const rendering::XCanvas* pCanvas, 665cdf0e10cSrcweir const uno::Reference< rendering::XBitmap >& xBitmap, 666cdf0e10cSrcweir const rendering::ViewState& viewState, 667cdf0e10cSrcweir const rendering::RenderState& renderState, 668cdf0e10cSrcweir bool bModulateColors ) 669cdf0e10cSrcweir { 670cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xBitmap.is(), 671cdf0e10cSrcweir "bitmap is NULL"); 672cdf0e10cSrcweir 673cdf0e10cSrcweir ::canvas::tools::verifyInput( renderState, 674cdf0e10cSrcweir BOOST_CURRENT_FUNCTION, 675cdf0e10cSrcweir mpDevice, 676cdf0e10cSrcweir 4, 677cdf0e10cSrcweir bModulateColors ? 3 : 0 ); 678cdf0e10cSrcweir 679cdf0e10cSrcweir if( mpOutDev ) 680cdf0e10cSrcweir { 681cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 682cdf0e10cSrcweir setupOutDevState( viewState, renderState, IGNORE_COLOR ); 683cdf0e10cSrcweir 684cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 685cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform(aMatrix, viewState, renderState); 686cdf0e10cSrcweir 687cdf0e10cSrcweir ::basegfx::B2DPoint aOutputPos( 0.0, 0.0 ); 688cdf0e10cSrcweir aOutputPos *= aMatrix; 689cdf0e10cSrcweir 690cdf0e10cSrcweir BitmapEx aBmpEx( tools::bitmapExFromXBitmap(xBitmap) ); 691cdf0e10cSrcweir 692cdf0e10cSrcweir // TODO(F2): Implement modulation again for other color 693cdf0e10cSrcweir // channels (currently, works only for alpha). Note: this 694cdf0e10cSrcweir // is already implemented in transformBitmap() 695cdf0e10cSrcweir if( bModulateColors && 696cdf0e10cSrcweir renderState.DeviceColor.getLength() > 3 ) 697cdf0e10cSrcweir { 698cdf0e10cSrcweir // optimize away the case where alpha modulation value 699cdf0e10cSrcweir // is 1.0 - we then simply switch off modulation at all 700cdf0e10cSrcweir bModulateColors = !::rtl::math::approxEqual( 701cdf0e10cSrcweir renderState.DeviceColor[3], 1.0); 702cdf0e10cSrcweir } 703cdf0e10cSrcweir 704cdf0e10cSrcweir // check whether we can render bitmap as-is: must not 705cdf0e10cSrcweir // modulate colors, matrix must either be the identity 706cdf0e10cSrcweir // transform (that's clear), _or_ contain only 707cdf0e10cSrcweir // translational components. 708cdf0e10cSrcweir if( !bModulateColors && 709cdf0e10cSrcweir (aMatrix.isIdentity() || 710cdf0e10cSrcweir (::basegfx::fTools::equalZero( aMatrix.get(0,1) ) && 711cdf0e10cSrcweir ::basegfx::fTools::equalZero( aMatrix.get(1,0) ) && 712cdf0e10cSrcweir ::rtl::math::approxEqual(aMatrix.get(0,0), 1.0) && 713cdf0e10cSrcweir ::rtl::math::approxEqual(aMatrix.get(1,1), 1.0)) ) ) 714cdf0e10cSrcweir { 715cdf0e10cSrcweir // optimized case: identity matrix, or only 716cdf0e10cSrcweir // translational components. 717cdf0e10cSrcweir mpOutDev->getOutDev().DrawBitmapEx( ::vcl::unotools::pointFromB2DPoint( aOutputPos ), 718cdf0e10cSrcweir aBmpEx ); 719cdf0e10cSrcweir 720cdf0e10cSrcweir if( mp2ndOutDev ) 721cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawBitmapEx( ::vcl::unotools::pointFromB2DPoint( aOutputPos ), 722cdf0e10cSrcweir aBmpEx ); 723cdf0e10cSrcweir 724cdf0e10cSrcweir // Returning a cache object is not useful, the XBitmap 725cdf0e10cSrcweir // itself serves this purpose 726cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 727cdf0e10cSrcweir } 728cdf0e10cSrcweir else 729cdf0e10cSrcweir { 730cdf0e10cSrcweir // Matrix contains non-trivial transformation (or 731cdf0e10cSrcweir // color modulation is requested), decompose to check 732cdf0e10cSrcweir // whether GraphicObject suffices 733cdf0e10cSrcweir ::basegfx::B2DVector aScale; 734cdf0e10cSrcweir double nRotate; 735cdf0e10cSrcweir double nShearX; 736cdf0e10cSrcweir aMatrix.decompose( aScale, aOutputPos, nRotate, nShearX ); 737cdf0e10cSrcweir 738cdf0e10cSrcweir GraphicAttr aGrfAttr; 739cdf0e10cSrcweir GraphicObjectSharedPtr pGrfObj; 740cdf0e10cSrcweir 741cdf0e10cSrcweir ::Size aBmpSize( aBmpEx.GetSizePixel() ); 742cdf0e10cSrcweir 743cdf0e10cSrcweir // setup alpha modulation 744cdf0e10cSrcweir if( bModulateColors ) 745cdf0e10cSrcweir { 746cdf0e10cSrcweir const double nAlphaModulation( renderState.DeviceColor[3] ); 747cdf0e10cSrcweir 748cdf0e10cSrcweir // TODO(F1): Note that the GraphicManager has a 749cdf0e10cSrcweir // subtle difference in how it calculates the 750cdf0e10cSrcweir // resulting alpha value: it's using the inverse 751cdf0e10cSrcweir // alpha values (i.e. 'transparency'), and 752cdf0e10cSrcweir // calculates transOrig + transModulate, instead 753cdf0e10cSrcweir // of transOrig + transModulate - 754cdf0e10cSrcweir // transOrig*transModulate (which would be 755cdf0e10cSrcweir // equivalent to the origAlpha*modulateAlpha the 756cdf0e10cSrcweir // DX canvas performs) 757cdf0e10cSrcweir aGrfAttr.SetTransparency( 758cdf0e10cSrcweir static_cast< sal_uInt8 >( 759cdf0e10cSrcweir ::basegfx::fround( 255.0*( 1.0 - nAlphaModulation ) ) ) ); 760cdf0e10cSrcweir } 761cdf0e10cSrcweir 762cdf0e10cSrcweir if( ::basegfx::fTools::equalZero( nShearX ) ) 763cdf0e10cSrcweir { 764cdf0e10cSrcweir // no shear, GraphicObject is enough (the 765cdf0e10cSrcweir // GraphicObject only supports scaling, rotation 766cdf0e10cSrcweir // and translation) 767cdf0e10cSrcweir 768cdf0e10cSrcweir // #i75339# don't apply mirror flags, having 769cdf0e10cSrcweir // negative size values is enough to make 770cdf0e10cSrcweir // GraphicObject flip the bitmap 771cdf0e10cSrcweir 772cdf0e10cSrcweir // The angle has to be mapped from radian to tenths of 773cdf0e10cSrcweir // degress with the orientation reversed: [0,2Pi) -> 774cdf0e10cSrcweir // (3600,0]. Note that the original angle may have 775cdf0e10cSrcweir // values outside the [0,2Pi) interval. 776cdf0e10cSrcweir const double nAngleInTenthOfDegrees (3600.0 - nRotate * 3600.0 / (2*M_PI)); 777cdf0e10cSrcweir aGrfAttr.SetRotation( static_cast< sal_uInt16 >(::basegfx::fround(nAngleInTenthOfDegrees)) ); 778cdf0e10cSrcweir 779cdf0e10cSrcweir pGrfObj.reset( new GraphicObject( aBmpEx ) ); 780cdf0e10cSrcweir } 781cdf0e10cSrcweir else 782cdf0e10cSrcweir { 783cdf0e10cSrcweir // modify output position, to account for the fact 784cdf0e10cSrcweir // that transformBitmap() always normalizes its output 785cdf0e10cSrcweir // bitmap into the smallest enclosing box. 786cdf0e10cSrcweir ::basegfx::B2DRectangle aDestRect; 787cdf0e10cSrcweir ::canvas::tools::calcTransformedRectBounds( aDestRect, 788cdf0e10cSrcweir ::basegfx::B2DRectangle(0, 789cdf0e10cSrcweir 0, 790cdf0e10cSrcweir aBmpSize.Width(), 791cdf0e10cSrcweir aBmpSize.Height()), 792cdf0e10cSrcweir aMatrix ); 793cdf0e10cSrcweir 794cdf0e10cSrcweir aOutputPos.setX( aDestRect.getMinX() ); 795cdf0e10cSrcweir aOutputPos.setY( aDestRect.getMinY() ); 796cdf0e10cSrcweir 797cdf0e10cSrcweir // complex transformation, use generic affine bitmap 798cdf0e10cSrcweir // transformation 799cdf0e10cSrcweir aBmpEx = tools::transformBitmap( aBmpEx, 800cdf0e10cSrcweir aMatrix, 801cdf0e10cSrcweir renderState.DeviceColor, 802cdf0e10cSrcweir tools::MODULATE_NONE ); 803cdf0e10cSrcweir 804cdf0e10cSrcweir pGrfObj.reset( new GraphicObject( aBmpEx ) ); 805cdf0e10cSrcweir 806cdf0e10cSrcweir // clear scale values, generated bitmap already 807cdf0e10cSrcweir // contains scaling 808cdf0e10cSrcweir aScale.setX( 1.0 ); aScale.setY( 1.0 ); 809cdf0e10cSrcweir 810cdf0e10cSrcweir // update bitmap size, bitmap has changed above. 811cdf0e10cSrcweir aBmpSize = aBmpEx.GetSizePixel(); 812cdf0e10cSrcweir } 813cdf0e10cSrcweir 814cdf0e10cSrcweir // output GraphicObject 815cdf0e10cSrcweir const ::Point aPt( ::vcl::unotools::pointFromB2DPoint( aOutputPos ) ); 816cdf0e10cSrcweir const ::Size aSz( ::basegfx::fround( aScale.getX() * aBmpSize.Width() ), 817cdf0e10cSrcweir ::basegfx::fround( aScale.getY() * aBmpSize.Height() ) ); 818cdf0e10cSrcweir 819cdf0e10cSrcweir pGrfObj->Draw( &mpOutDev->getOutDev(), 820cdf0e10cSrcweir aPt, 821cdf0e10cSrcweir aSz, 822cdf0e10cSrcweir &aGrfAttr ); 823cdf0e10cSrcweir 824cdf0e10cSrcweir if( mp2ndOutDev ) 825cdf0e10cSrcweir pGrfObj->Draw( &mp2ndOutDev->getOutDev(), 826cdf0e10cSrcweir aPt, 827cdf0e10cSrcweir aSz, 828cdf0e10cSrcweir &aGrfAttr ); 829cdf0e10cSrcweir 830cdf0e10cSrcweir // created GraphicObject, which possibly cached 831cdf0e10cSrcweir // display bitmap - return cache object, to retain 832cdf0e10cSrcweir // that information. 833cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >( 834cdf0e10cSrcweir new CachedBitmap( pGrfObj, 835cdf0e10cSrcweir aPt, 836cdf0e10cSrcweir aSz, 837cdf0e10cSrcweir aGrfAttr, 838cdf0e10cSrcweir viewState, 839cdf0e10cSrcweir renderState, 840cdf0e10cSrcweir // cast away const, need to 841cdf0e10cSrcweir // change refcount (as this is 842cdf0e10cSrcweir // ~invisible to client code, 843cdf0e10cSrcweir // still logically const) 844cdf0e10cSrcweir const_cast< rendering::XCanvas* >(pCanvas)) ); 845cdf0e10cSrcweir } 846cdf0e10cSrcweir } 847cdf0e10cSrcweir 848cdf0e10cSrcweir // Nothing rendered 849cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 850cdf0e10cSrcweir } 851cdf0e10cSrcweir 852cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmap( const rendering::XCanvas* pCanvas, 853cdf0e10cSrcweir const uno::Reference< rendering::XBitmap >& xBitmap, 854cdf0e10cSrcweir const rendering::ViewState& viewState, 855cdf0e10cSrcweir const rendering::RenderState& renderState ) 856cdf0e10cSrcweir { 857cdf0e10cSrcweir return implDrawBitmap( pCanvas, 858cdf0e10cSrcweir xBitmap, 859cdf0e10cSrcweir viewState, 860cdf0e10cSrcweir renderState, 861cdf0e10cSrcweir false ); 862cdf0e10cSrcweir } 863cdf0e10cSrcweir 864cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas, 865cdf0e10cSrcweir const uno::Reference< rendering::XBitmap >& xBitmap, 866cdf0e10cSrcweir const rendering::ViewState& viewState, 867cdf0e10cSrcweir const rendering::RenderState& renderState ) 868cdf0e10cSrcweir { 869cdf0e10cSrcweir return implDrawBitmap( pCanvas, 870cdf0e10cSrcweir xBitmap, 871cdf0e10cSrcweir viewState, 872cdf0e10cSrcweir renderState, 873cdf0e10cSrcweir true ); 874cdf0e10cSrcweir } 875cdf0e10cSrcweir 876cdf0e10cSrcweir uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice() 877cdf0e10cSrcweir { 878cdf0e10cSrcweir // cast away const, need to change refcount (as this is 879cdf0e10cSrcweir // ~invisible to client code, still logically const) 880cdf0e10cSrcweir return uno::Reference< rendering::XGraphicDevice >(mpDevice); 881cdf0e10cSrcweir } 882cdf0e10cSrcweir 883cdf0e10cSrcweir void CanvasHelper::copyRect( const rendering::XCanvas* , 884cdf0e10cSrcweir const uno::Reference< rendering::XBitmapCanvas >& , 885cdf0e10cSrcweir const geometry::RealRectangle2D& , 886cdf0e10cSrcweir const rendering::ViewState& , 887cdf0e10cSrcweir const rendering::RenderState& , 888cdf0e10cSrcweir const geometry::RealRectangle2D& , 889cdf0e10cSrcweir const rendering::ViewState& , 890cdf0e10cSrcweir const rendering::RenderState& ) 891cdf0e10cSrcweir { 892cdf0e10cSrcweir // TODO(F1) 893cdf0e10cSrcweir } 894cdf0e10cSrcweir 895cdf0e10cSrcweir geometry::IntegerSize2D CanvasHelper::getSize() 896cdf0e10cSrcweir { 897cdf0e10cSrcweir if( !mpOutDev.get() ) 898cdf0e10cSrcweir return geometry::IntegerSize2D(); // we're disposed 899cdf0e10cSrcweir 900cdf0e10cSrcweir return ::vcl::unotools::integerSize2DFromSize( mpOutDev->getOutDev().GetOutputSizePixel() ); 901cdf0e10cSrcweir } 902cdf0e10cSrcweir 903cdf0e10cSrcweir uno::Reference< rendering::XBitmap > CanvasHelper::getScaledBitmap( const geometry::RealSize2D& newSize, 904cdf0e10cSrcweir sal_Bool beFast ) 905cdf0e10cSrcweir { 906cdf0e10cSrcweir if( !mpOutDev.get() || !mpDevice ) 907cdf0e10cSrcweir return uno::Reference< rendering::XBitmap >(); // we're disposed 908cdf0e10cSrcweir 909cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 910cdf0e10cSrcweir 911cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 912cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 913cdf0e10cSrcweir 914cdf0e10cSrcweir // TODO(F2): Support alpha vdev canvas here 915cdf0e10cSrcweir const Point aEmptyPoint(0,0); 916cdf0e10cSrcweir const Size aBmpSize( rOutDev.GetOutputSizePixel() ); 917cdf0e10cSrcweir 918cdf0e10cSrcweir Bitmap aBitmap( rOutDev.GetBitmap(aEmptyPoint, aBmpSize) ); 919cdf0e10cSrcweir 920cdf0e10cSrcweir aBitmap.Scale( ::vcl::unotools::sizeFromRealSize2D(newSize), 921cdf0e10cSrcweir beFast ? BMP_SCALE_FAST : BMP_SCALE_INTERPOLATE ); 922cdf0e10cSrcweir 923cdf0e10cSrcweir return uno::Reference< rendering::XBitmap >( 924cdf0e10cSrcweir new CanvasBitmap( aBitmap, *mpDevice, mpOutDev ) ); 925cdf0e10cSrcweir } 926cdf0e10cSrcweir 927cdf0e10cSrcweir uno::Sequence< sal_Int8 > CanvasHelper::getData( rendering::IntegerBitmapLayout& rLayout, 928cdf0e10cSrcweir const geometry::IntegerRectangle2D& rect ) 929cdf0e10cSrcweir { 930cdf0e10cSrcweir if( !mpOutDev.get() ) 931cdf0e10cSrcweir return uno::Sequence< sal_Int8 >(); // we're disposed 932cdf0e10cSrcweir 933cdf0e10cSrcweir rLayout = getMemoryLayout(); 934cdf0e10cSrcweir 935cdf0e10cSrcweir // TODO(F2): Support alpha canvas here 936cdf0e10cSrcweir const Rectangle aRect( ::vcl::unotools::rectangleFromIntegerRectangle2D(rect) ); 937cdf0e10cSrcweir 938cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 939cdf0e10cSrcweir 940cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 941cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 942cdf0e10cSrcweir 943cdf0e10cSrcweir Bitmap aBitmap( rOutDev.GetBitmap(aRect.TopLeft(), 944cdf0e10cSrcweir aRect.GetSize()) ); 945cdf0e10cSrcweir 946cdf0e10cSrcweir ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(), 947cdf0e10cSrcweir aBitmap ); 948cdf0e10cSrcweir 949cdf0e10cSrcweir ENSURE_OR_THROW( pReadAccess.get() != NULL, 950cdf0e10cSrcweir "Could not acquire read access to OutDev bitmap" ); 951cdf0e10cSrcweir 952cdf0e10cSrcweir const sal_Int32 nWidth( rect.X2 - rect.X1 ); 953cdf0e10cSrcweir const sal_Int32 nHeight( rect.Y2 - rect.Y1 ); 954cdf0e10cSrcweir 955cdf0e10cSrcweir rLayout.ScanLines = nHeight; 956cdf0e10cSrcweir rLayout.ScanLineBytes = nWidth*4; 957cdf0e10cSrcweir rLayout.ScanLineStride = rLayout.ScanLineBytes; 958cdf0e10cSrcweir 959cdf0e10cSrcweir uno::Sequence< sal_Int8 > aRes( 4*nWidth*nHeight ); 960cdf0e10cSrcweir sal_Int8* pRes = aRes.getArray(); 961cdf0e10cSrcweir 962cdf0e10cSrcweir int nCurrPos(0); 963cdf0e10cSrcweir for( int y=0; y<nHeight; ++y ) 964cdf0e10cSrcweir { 965cdf0e10cSrcweir for( int x=0; x<nWidth; ++x ) 966cdf0e10cSrcweir { 967cdf0e10cSrcweir pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetRed(); 968cdf0e10cSrcweir pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetGreen(); 969cdf0e10cSrcweir pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetBlue(); 970cdf0e10cSrcweir pRes[ nCurrPos++ ] = -1; 971cdf0e10cSrcweir } 972cdf0e10cSrcweir } 973cdf0e10cSrcweir 974cdf0e10cSrcweir return aRes; 975cdf0e10cSrcweir } 976cdf0e10cSrcweir 977cdf0e10cSrcweir void CanvasHelper::setData( const uno::Sequence< sal_Int8 >& data, 978cdf0e10cSrcweir const rendering::IntegerBitmapLayout& aLayout, 979cdf0e10cSrcweir const geometry::IntegerRectangle2D& rect ) 980cdf0e10cSrcweir { 981cdf0e10cSrcweir if( !mpOutDev.get() ) 982cdf0e10cSrcweir return; // we're disposed 983cdf0e10cSrcweir 984cdf0e10cSrcweir const rendering::IntegerBitmapLayout aRefLayout( getMemoryLayout() ); 985cdf0e10cSrcweir ENSURE_ARG_OR_THROW( aRefLayout.PlaneStride != aLayout.PlaneStride || 986cdf0e10cSrcweir aRefLayout.ColorSpace != aLayout.ColorSpace || 987cdf0e10cSrcweir aRefLayout.Palette != aLayout.Palette || 988cdf0e10cSrcweir aRefLayout.IsMsbFirst != aLayout.IsMsbFirst, 989cdf0e10cSrcweir "Mismatching memory layout" ); 990cdf0e10cSrcweir 991cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 992cdf0e10cSrcweir 993cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 994cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 995cdf0e10cSrcweir 996cdf0e10cSrcweir const Rectangle aRect( ::vcl::unotools::rectangleFromIntegerRectangle2D(rect) ); 997cdf0e10cSrcweir const sal_uInt16 nBitCount( ::std::min( (sal_uInt16)24U, 998cdf0e10cSrcweir (sal_uInt16)rOutDev.GetBitCount() ) ); 999cdf0e10cSrcweir const BitmapPalette* pPalette = NULL; 1000cdf0e10cSrcweir 1001cdf0e10cSrcweir if( nBitCount <= 8 ) 1002cdf0e10cSrcweir { 1003cdf0e10cSrcweir // TODO(Q1): Extract this to a common place, e.g. GraphicDevice 1004cdf0e10cSrcweir 1005cdf0e10cSrcweir // try to determine palette from output device (by 1006cdf0e10cSrcweir // extracting a 1,1 bitmap, and querying it) 1007cdf0e10cSrcweir const Point aEmptyPoint; 1008cdf0e10cSrcweir const Size aSize(1,1); 1009cdf0e10cSrcweir Bitmap aTmpBitmap( rOutDev.GetBitmap( aEmptyPoint, 1010cdf0e10cSrcweir aSize ) ); 1011cdf0e10cSrcweir 1012cdf0e10cSrcweir ScopedBitmapReadAccess pReadAccess( aTmpBitmap.AcquireReadAccess(), 1013cdf0e10cSrcweir aTmpBitmap ); 1014cdf0e10cSrcweir 1015cdf0e10cSrcweir pPalette = &pReadAccess->GetPalette(); 1016cdf0e10cSrcweir } 1017cdf0e10cSrcweir 1018cdf0e10cSrcweir // TODO(F2): Support alpha canvas here 1019cdf0e10cSrcweir Bitmap aBitmap( aRect.GetSize(), nBitCount, pPalette ); 1020cdf0e10cSrcweir 1021cdf0e10cSrcweir bool bCopyBack( false ); // only copy something back, if we 1022cdf0e10cSrcweir // actually changed some pixel 1023cdf0e10cSrcweir { 1024cdf0e10cSrcweir ScopedBitmapWriteAccess pWriteAccess( aBitmap.AcquireWriteAccess(), 1025cdf0e10cSrcweir aBitmap ); 1026cdf0e10cSrcweir 1027cdf0e10cSrcweir ENSURE_OR_THROW( pWriteAccess.get() != NULL, 1028cdf0e10cSrcweir "Could not acquire write access to OutDev bitmap" ); 1029cdf0e10cSrcweir 1030cdf0e10cSrcweir // for the time being, always read as RGB 1031cdf0e10cSrcweir const sal_Int32 nWidth( rect.X2 - rect.X1 ); 1032cdf0e10cSrcweir const sal_Int32 nHeight( rect.Y2 - rect.Y1 ); 1033cdf0e10cSrcweir int x, y, nCurrPos(0); 1034cdf0e10cSrcweir for( y=0; y<nHeight; ++y ) 1035cdf0e10cSrcweir { 1036cdf0e10cSrcweir switch( pWriteAccess->GetScanlineFormat() ) 1037cdf0e10cSrcweir { 1038cdf0e10cSrcweir case BMP_FORMAT_8BIT_PAL: 1039cdf0e10cSrcweir { 1040cdf0e10cSrcweir Scanline pScan = pWriteAccess->GetScanline( y ); 1041cdf0e10cSrcweir 1042cdf0e10cSrcweir for( x=0; x<nWidth; ++x ) 1043cdf0e10cSrcweir { 1044cdf0e10cSrcweir *pScan++ = (sal_uInt8)pWriteAccess->GetBestPaletteIndex( 1045cdf0e10cSrcweir BitmapColor( data[ nCurrPos ], 1046cdf0e10cSrcweir data[ nCurrPos+1 ], 1047cdf0e10cSrcweir data[ nCurrPos+2 ] ) ); 1048cdf0e10cSrcweir 1049cdf0e10cSrcweir nCurrPos += 4; 1050cdf0e10cSrcweir } 1051cdf0e10cSrcweir } 1052cdf0e10cSrcweir break; 1053cdf0e10cSrcweir 1054cdf0e10cSrcweir case BMP_FORMAT_24BIT_TC_BGR: 1055cdf0e10cSrcweir { 1056cdf0e10cSrcweir Scanline pScan = pWriteAccess->GetScanline( y ); 1057cdf0e10cSrcweir 1058cdf0e10cSrcweir for( x=0; x<nWidth; ++x ) 1059cdf0e10cSrcweir { 1060cdf0e10cSrcweir *pScan++ = data[ nCurrPos+2 ]; 1061cdf0e10cSrcweir *pScan++ = data[ nCurrPos+1 ]; 1062cdf0e10cSrcweir *pScan++ = data[ nCurrPos ]; 1063cdf0e10cSrcweir 1064cdf0e10cSrcweir nCurrPos += 4; 1065cdf0e10cSrcweir } 1066cdf0e10cSrcweir } 1067cdf0e10cSrcweir break; 1068cdf0e10cSrcweir 1069cdf0e10cSrcweir case BMP_FORMAT_24BIT_TC_RGB: 1070cdf0e10cSrcweir { 1071cdf0e10cSrcweir Scanline pScan = pWriteAccess->GetScanline( y ); 1072cdf0e10cSrcweir 1073cdf0e10cSrcweir for( x=0; x<nWidth; ++x ) 1074cdf0e10cSrcweir { 1075cdf0e10cSrcweir *pScan++ = data[ nCurrPos ]; 1076cdf0e10cSrcweir *pScan++ = data[ nCurrPos+1 ]; 1077cdf0e10cSrcweir *pScan++ = data[ nCurrPos+2 ]; 1078cdf0e10cSrcweir 1079cdf0e10cSrcweir nCurrPos += 4; 1080cdf0e10cSrcweir } 1081cdf0e10cSrcweir } 1082cdf0e10cSrcweir break; 1083cdf0e10cSrcweir 1084cdf0e10cSrcweir default: 1085cdf0e10cSrcweir { 1086cdf0e10cSrcweir for( x=0; x<nWidth; ++x ) 1087cdf0e10cSrcweir { 1088cdf0e10cSrcweir pWriteAccess->SetPixel( y, x, BitmapColor( data[ nCurrPos ], 1089cdf0e10cSrcweir data[ nCurrPos+1 ], 1090cdf0e10cSrcweir data[ nCurrPos+2 ] ) ); 1091cdf0e10cSrcweir nCurrPos += 4; 1092cdf0e10cSrcweir } 1093cdf0e10cSrcweir } 1094cdf0e10cSrcweir break; 1095cdf0e10cSrcweir } 1096cdf0e10cSrcweir } 1097cdf0e10cSrcweir 1098cdf0e10cSrcweir bCopyBack = true; 1099cdf0e10cSrcweir } 1100cdf0e10cSrcweir 1101cdf0e10cSrcweir // copy back only here, since the BitmapAccessors must be 1102cdf0e10cSrcweir // destroyed beforehand 1103cdf0e10cSrcweir if( bCopyBack ) 1104cdf0e10cSrcweir { 1105cdf0e10cSrcweir // TODO(F2): Support alpha canvas here 1106cdf0e10cSrcweir rOutDev.DrawBitmap(aRect.TopLeft(), aBitmap); 1107cdf0e10cSrcweir } 1108cdf0e10cSrcweir } 1109cdf0e10cSrcweir 1110cdf0e10cSrcweir void CanvasHelper::setPixel( const uno::Sequence< sal_Int8 >& color, 1111cdf0e10cSrcweir const rendering::IntegerBitmapLayout& rLayout, 1112cdf0e10cSrcweir const geometry::IntegerPoint2D& pos ) 1113cdf0e10cSrcweir { 1114cdf0e10cSrcweir if( !mpOutDev.get() ) 1115cdf0e10cSrcweir return; // we're disposed 1116cdf0e10cSrcweir 1117cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 1118cdf0e10cSrcweir 1119cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 1120cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 1121cdf0e10cSrcweir 1122cdf0e10cSrcweir const Size aBmpSize( rOutDev.GetOutputSizePixel() ); 1123cdf0e10cSrcweir 1124cdf0e10cSrcweir ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aBmpSize.Width(), 1125cdf0e10cSrcweir "X coordinate out of bounds" ); 1126cdf0e10cSrcweir ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aBmpSize.Height(), 1127cdf0e10cSrcweir "Y coordinate out of bounds" ); 1128cdf0e10cSrcweir ENSURE_ARG_OR_THROW( color.getLength() > 3, 1129cdf0e10cSrcweir "not enough color components" ); 1130cdf0e10cSrcweir 1131cdf0e10cSrcweir const rendering::IntegerBitmapLayout aRefLayout( getMemoryLayout() ); 1132cdf0e10cSrcweir ENSURE_ARG_OR_THROW( aRefLayout.PlaneStride != rLayout.PlaneStride || 1133cdf0e10cSrcweir aRefLayout.ColorSpace != rLayout.ColorSpace || 1134cdf0e10cSrcweir aRefLayout.Palette != rLayout.Palette || 1135cdf0e10cSrcweir aRefLayout.IsMsbFirst != rLayout.IsMsbFirst, 1136cdf0e10cSrcweir "Mismatching memory layout" ); 1137cdf0e10cSrcweir 1138cdf0e10cSrcweir // TODO(F2): Support alpha canvas here 1139cdf0e10cSrcweir rOutDev.DrawPixel( ::vcl::unotools::pointFromIntegerPoint2D( pos ), 1140cdf0e10cSrcweir ::canvas::tools::stdIntSequenceToColor( color )); 1141cdf0e10cSrcweir } 1142cdf0e10cSrcweir 1143cdf0e10cSrcweir uno::Sequence< sal_Int8 > CanvasHelper::getPixel( rendering::IntegerBitmapLayout& rLayout, 1144cdf0e10cSrcweir const geometry::IntegerPoint2D& pos ) 1145cdf0e10cSrcweir { 1146cdf0e10cSrcweir if( !mpOutDev.get() ) 1147cdf0e10cSrcweir return uno::Sequence< sal_Int8 >(); // we're disposed 1148cdf0e10cSrcweir 1149cdf0e10cSrcweir rLayout = getMemoryLayout(); 1150cdf0e10cSrcweir rLayout.ScanLines = 1; 1151cdf0e10cSrcweir rLayout.ScanLineBytes = 4; 1152cdf0e10cSrcweir rLayout.ScanLineStride = rLayout.ScanLineBytes; 1153cdf0e10cSrcweir 1154cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 1155cdf0e10cSrcweir 1156cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 1157cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 1158cdf0e10cSrcweir 1159cdf0e10cSrcweir const Size aBmpSize( rOutDev.GetOutputSizePixel() ); 1160cdf0e10cSrcweir 1161cdf0e10cSrcweir ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aBmpSize.Width(), 1162cdf0e10cSrcweir "X coordinate out of bounds" ); 1163cdf0e10cSrcweir ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aBmpSize.Height(), 1164cdf0e10cSrcweir "Y coordinate out of bounds" ); 1165cdf0e10cSrcweir 1166cdf0e10cSrcweir // TODO(F2): Support alpha canvas here 1167cdf0e10cSrcweir return ::canvas::tools::colorToStdIntSequence( 1168cdf0e10cSrcweir rOutDev.GetPixel( 1169cdf0e10cSrcweir ::vcl::unotools::pointFromIntegerPoint2D( pos ))); 1170cdf0e10cSrcweir } 1171cdf0e10cSrcweir 1172cdf0e10cSrcweir rendering::IntegerBitmapLayout CanvasHelper::getMemoryLayout() 1173cdf0e10cSrcweir { 1174cdf0e10cSrcweir if( !mpOutDev.get() ) 1175cdf0e10cSrcweir return rendering::IntegerBitmapLayout(); // we're disposed 1176cdf0e10cSrcweir 1177cdf0e10cSrcweir return ::canvas::tools::getStdMemoryLayout(getSize()); 1178cdf0e10cSrcweir } 1179cdf0e10cSrcweir 1180cdf0e10cSrcweir int CanvasHelper::setupOutDevState( const rendering::ViewState& viewState, 1181cdf0e10cSrcweir const rendering::RenderState& renderState, 1182cdf0e10cSrcweir ColorType eColorType ) const 1183cdf0e10cSrcweir { 1184cdf0e10cSrcweir ENSURE_OR_THROW( mpOutDev.get(), 1185cdf0e10cSrcweir "outdev null. Are we disposed?" ); 1186cdf0e10cSrcweir 1187cdf0e10cSrcweir ::canvas::tools::verifyInput( renderState, 1188cdf0e10cSrcweir BOOST_CURRENT_FUNCTION, 1189cdf0e10cSrcweir mpDevice, 1190cdf0e10cSrcweir 2, 1191cdf0e10cSrcweir eColorType == IGNORE_COLOR ? 0 : 3 ); 1192cdf0e10cSrcweir 1193cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 1194cdf0e10cSrcweir OutputDevice* p2ndOutDev = NULL; 1195cdf0e10cSrcweir 1196cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 1197cdf0e10cSrcweir 1198cdf0e10cSrcweir if( mp2ndOutDev ) 1199cdf0e10cSrcweir p2ndOutDev = &mp2ndOutDev->getOutDev(); 1200cdf0e10cSrcweir 1201cdf0e10cSrcweir int nTransparency(0); 1202cdf0e10cSrcweir 1203cdf0e10cSrcweir // TODO(P2): Don't change clipping all the time, maintain current clip 1204cdf0e10cSrcweir // state and change only when update is necessary 1205cdf0e10cSrcweir 1206cdf0e10cSrcweir // accumulate non-empty clips into one region 1207cdf0e10cSrcweir // ========================================== 1208cdf0e10cSrcweir 1209cdf0e10cSrcweir Region aClipRegion( REGION_NULL ); 1210cdf0e10cSrcweir 1211cdf0e10cSrcweir if( viewState.Clip.is() ) 1212cdf0e10cSrcweir { 1213cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aClipPoly( 1214cdf0e10cSrcweir ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(viewState.Clip) ); 1215cdf0e10cSrcweir 1216cdf0e10cSrcweir if( aClipPoly.count() ) 1217cdf0e10cSrcweir { 1218cdf0e10cSrcweir // setup non-empty clipping 1219cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 1220cdf0e10cSrcweir aClipPoly.transform( 1221cdf0e10cSrcweir ::basegfx::unotools::homMatrixFromAffineMatrix( aMatrix, 1222cdf0e10cSrcweir viewState.AffineTransform ) ); 1223cdf0e10cSrcweir 1224cdf0e10cSrcweir aClipRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) ); 1225cdf0e10cSrcweir } 1226cdf0e10cSrcweir else 1227cdf0e10cSrcweir { 1228cdf0e10cSrcweir // clip polygon is empty 1229cdf0e10cSrcweir aClipRegion.SetEmpty(); 1230cdf0e10cSrcweir } 1231cdf0e10cSrcweir } 1232cdf0e10cSrcweir 1233cdf0e10cSrcweir if( renderState.Clip.is() ) 1234cdf0e10cSrcweir { 1235cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aClipPoly( 1236cdf0e10cSrcweir ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(renderState.Clip) ); 1237cdf0e10cSrcweir 1238cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 1239cdf0e10cSrcweir aClipPoly.transform( 1240cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform( aMatrix, 1241cdf0e10cSrcweir viewState, 1242cdf0e10cSrcweir renderState ) ); 1243cdf0e10cSrcweir 1244cdf0e10cSrcweir if( aClipPoly.count() ) 1245cdf0e10cSrcweir { 1246cdf0e10cSrcweir // setup non-empty clipping 1247cdf0e10cSrcweir Region aRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) ); 1248cdf0e10cSrcweir aClipRegion.Intersect( aRegion ); 1249cdf0e10cSrcweir } 1250cdf0e10cSrcweir else 1251cdf0e10cSrcweir { 1252cdf0e10cSrcweir // clip polygon is empty 1253cdf0e10cSrcweir aClipRegion.SetEmpty(); 1254cdf0e10cSrcweir } 1255cdf0e10cSrcweir } 1256cdf0e10cSrcweir 1257cdf0e10cSrcweir // setup accumulated clip region. Note that setting an 1258cdf0e10cSrcweir // empty clip region denotes "clip everything" on the 1259cdf0e10cSrcweir // OutputDevice (which is why we translate that into 1260cdf0e10cSrcweir // SetClipRegion() here). When both view and render clip 1261cdf0e10cSrcweir // are empty, aClipRegion remains default-constructed, 1262cdf0e10cSrcweir // i.e. empty, too. 1263cdf0e10cSrcweir if( aClipRegion.IsNull() ) 1264cdf0e10cSrcweir { 1265cdf0e10cSrcweir rOutDev.SetClipRegion(); 1266cdf0e10cSrcweir 1267cdf0e10cSrcweir if( p2ndOutDev ) 1268cdf0e10cSrcweir p2ndOutDev->SetClipRegion(); 1269cdf0e10cSrcweir } 1270cdf0e10cSrcweir else 1271cdf0e10cSrcweir { 1272cdf0e10cSrcweir rOutDev.SetClipRegion( aClipRegion ); 1273cdf0e10cSrcweir 1274cdf0e10cSrcweir if( p2ndOutDev ) 1275cdf0e10cSrcweir p2ndOutDev->SetClipRegion( aClipRegion ); 1276cdf0e10cSrcweir } 1277cdf0e10cSrcweir 1278cdf0e10cSrcweir if( eColorType != IGNORE_COLOR ) 1279cdf0e10cSrcweir { 1280cdf0e10cSrcweir Color aColor( COL_WHITE ); 1281cdf0e10cSrcweir 1282cdf0e10cSrcweir if( renderState.DeviceColor.getLength() > 2 ) 1283cdf0e10cSrcweir { 1284cdf0e10cSrcweir aColor = ::vcl::unotools::stdColorSpaceSequenceToColor( 1285cdf0e10cSrcweir renderState.DeviceColor ); 1286cdf0e10cSrcweir } 1287cdf0e10cSrcweir 1288cdf0e10cSrcweir // extract alpha, and make color opaque 1289cdf0e10cSrcweir // afterwards. Otherwise, OutputDevice won't draw anything 1290cdf0e10cSrcweir nTransparency = aColor.GetTransparency(); 1291cdf0e10cSrcweir aColor.SetTransparency(0); 1292cdf0e10cSrcweir 1293cdf0e10cSrcweir switch( eColorType ) 1294cdf0e10cSrcweir { 1295cdf0e10cSrcweir case LINE_COLOR: 1296cdf0e10cSrcweir rOutDev.SetLineColor( aColor ); 1297cdf0e10cSrcweir rOutDev.SetFillColor(); 1298cdf0e10cSrcweir 1299cdf0e10cSrcweir if( p2ndOutDev ) 1300cdf0e10cSrcweir { 1301cdf0e10cSrcweir p2ndOutDev->SetLineColor( aColor ); 1302cdf0e10cSrcweir p2ndOutDev->SetFillColor(); 1303cdf0e10cSrcweir } 1304cdf0e10cSrcweir break; 1305cdf0e10cSrcweir 1306cdf0e10cSrcweir case FILL_COLOR: 1307cdf0e10cSrcweir rOutDev.SetFillColor( aColor ); 1308cdf0e10cSrcweir rOutDev.SetLineColor(); 1309cdf0e10cSrcweir 1310cdf0e10cSrcweir if( p2ndOutDev ) 1311cdf0e10cSrcweir { 1312cdf0e10cSrcweir p2ndOutDev->SetFillColor( aColor ); 1313cdf0e10cSrcweir p2ndOutDev->SetLineColor(); 1314cdf0e10cSrcweir } 1315cdf0e10cSrcweir break; 1316cdf0e10cSrcweir 1317cdf0e10cSrcweir case TEXT_COLOR: 1318cdf0e10cSrcweir rOutDev.SetTextColor( aColor ); 1319cdf0e10cSrcweir 1320cdf0e10cSrcweir if( p2ndOutDev ) 1321cdf0e10cSrcweir p2ndOutDev->SetTextColor( aColor ); 1322cdf0e10cSrcweir break; 1323cdf0e10cSrcweir 1324cdf0e10cSrcweir default: 1325cdf0e10cSrcweir ENSURE_OR_THROW( false, 1326cdf0e10cSrcweir "Unexpected color type"); 1327cdf0e10cSrcweir break; 1328cdf0e10cSrcweir } 1329cdf0e10cSrcweir } 1330cdf0e10cSrcweir 1331cdf0e10cSrcweir return nTransparency; 1332cdf0e10cSrcweir } 1333cdf0e10cSrcweir 1334cdf0e10cSrcweir bool CanvasHelper::setupTextOutput( ::Point& o_rOutPos, 1335cdf0e10cSrcweir const rendering::ViewState& viewState, 1336cdf0e10cSrcweir const rendering::RenderState& renderState, 1337cdf0e10cSrcweir const uno::Reference< rendering::XCanvasFont >& xFont ) const 1338cdf0e10cSrcweir { 1339cdf0e10cSrcweir ENSURE_OR_THROW( mpOutDev.get(), 1340cdf0e10cSrcweir "outdev null. Are we disposed?" ); 1341cdf0e10cSrcweir 1342cdf0e10cSrcweir setupOutDevState( viewState, renderState, TEXT_COLOR ); 1343cdf0e10cSrcweir 1344cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 1345cdf0e10cSrcweir 1346cdf0e10cSrcweir ::Font aVCLFont; 1347cdf0e10cSrcweir 1348cdf0e10cSrcweir CanvasFont* pFont = dynamic_cast< CanvasFont* >( xFont.get() ); 1349cdf0e10cSrcweir 1350cdf0e10cSrcweir ENSURE_ARG_OR_THROW( pFont, 1351cdf0e10cSrcweir "Font not compatible with this canvas" ); 1352cdf0e10cSrcweir 1353cdf0e10cSrcweir aVCLFont = pFont->getVCLFont(); 1354cdf0e10cSrcweir 1355cdf0e10cSrcweir Color aColor( COL_BLACK ); 1356cdf0e10cSrcweir 1357cdf0e10cSrcweir if( renderState.DeviceColor.getLength() > 2 ) 1358cdf0e10cSrcweir { 1359cdf0e10cSrcweir aColor = ::vcl::unotools::stdColorSpaceSequenceToColor( 1360cdf0e10cSrcweir renderState.DeviceColor ); 1361cdf0e10cSrcweir } 1362cdf0e10cSrcweir 1363cdf0e10cSrcweir // setup font color 1364cdf0e10cSrcweir aVCLFont.SetColor( aColor ); 1365cdf0e10cSrcweir aVCLFont.SetFillColor( aColor ); 1366cdf0e10cSrcweir 1367cdf0e10cSrcweir // no need to replicate this for mp2ndOutDev, we're modifying only aVCLFont here. 1368cdf0e10cSrcweir if( !tools::setupFontTransform( o_rOutPos, aVCLFont, viewState, renderState, rOutDev ) ) 1369cdf0e10cSrcweir return false; 1370cdf0e10cSrcweir 1371cdf0e10cSrcweir rOutDev.SetFont( aVCLFont ); 1372cdf0e10cSrcweir 1373cdf0e10cSrcweir if( mp2ndOutDev ) 1374cdf0e10cSrcweir mp2ndOutDev->getOutDev().SetFont( aVCLFont ); 1375cdf0e10cSrcweir 1376cdf0e10cSrcweir return true; 1377cdf0e10cSrcweir } 1378cdf0e10cSrcweir 1379cdf0e10cSrcweir bool CanvasHelper::repaint( const GraphicObjectSharedPtr& rGrf, 1380cdf0e10cSrcweir const rendering::ViewState& viewState, 1381cdf0e10cSrcweir const rendering::RenderState& renderState, 1382cdf0e10cSrcweir const ::Point& rPt, 1383cdf0e10cSrcweir const ::Size& rSz, 1384cdf0e10cSrcweir const GraphicAttr& rAttr ) const 1385cdf0e10cSrcweir { 1386cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( rGrf, 1387cdf0e10cSrcweir "Invalid Graphic" ); 1388cdf0e10cSrcweir 1389cdf0e10cSrcweir if( !mpOutDev ) 1390cdf0e10cSrcweir return false; // disposed 1391cdf0e10cSrcweir else 1392cdf0e10cSrcweir { 1393cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 1394cdf0e10cSrcweir setupOutDevState( viewState, renderState, IGNORE_COLOR ); 1395cdf0e10cSrcweir 1396cdf0e10cSrcweir if( !rGrf->Draw( &mpOutDev->getOutDev(), rPt, rSz, &rAttr ) ) 1397cdf0e10cSrcweir return false; 1398cdf0e10cSrcweir 1399cdf0e10cSrcweir // #i80779# Redraw also into mask outdev 1400cdf0e10cSrcweir if( mp2ndOutDev ) 1401cdf0e10cSrcweir return rGrf->Draw( &mp2ndOutDev->getOutDev(), rPt, rSz, &rAttr ); 1402cdf0e10cSrcweir 1403cdf0e10cSrcweir return true; 1404cdf0e10cSrcweir } 1405cdf0e10cSrcweir } 1406cdf0e10cSrcweir 1407cdf0e10cSrcweir void CanvasHelper::flush() const 1408cdf0e10cSrcweir { 1409cdf0e10cSrcweir if( mpOutDev && mpOutDev->getOutDev().GetOutDevType() == OUTDEV_WINDOW ) 1410cdf0e10cSrcweir { 1411cdf0e10cSrcweir // TODO(Q3): Evil downcast. And what's more, Window::Flush is 1412cdf0e10cSrcweir // not even const. Wah. 1413cdf0e10cSrcweir static_cast<Window&>(mpOutDev->getOutDev()).Flush(); 1414cdf0e10cSrcweir } 1415cdf0e10cSrcweir 1416cdf0e10cSrcweir if( mp2ndOutDev && mp2ndOutDev->getOutDev().GetOutDevType() == OUTDEV_WINDOW ) 1417cdf0e10cSrcweir { 1418cdf0e10cSrcweir // TODO(Q3): Evil downcast. And what's more, Window::Flush is 1419cdf0e10cSrcweir // not even const. Wah. 1420cdf0e10cSrcweir static_cast<Window&>(mp2ndOutDev->getOutDev()).Flush(); 1421cdf0e10cSrcweir } 1422cdf0e10cSrcweir } 1423cdf0e10cSrcweir 1424cdf0e10cSrcweir } 1425