| /************************************************************** |
| * |
| * 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_cppcanvas.hxx" |
| |
| #include <rtl/logfile.hxx> |
| |
| #include <com/sun/star/rendering/XCanvas.hpp> |
| #include <com/sun/star/rendering/TexturingMode.hpp> |
| |
| #include <tools/gen.hxx> |
| #include <vcl/canvastools.hxx> |
| |
| #include <basegfx/range/b2drectangle.hxx> |
| #include <basegfx/tools/canvastools.hxx> |
| #include <basegfx/polygon/b2dpolypolygon.hxx> |
| #include <basegfx/polygon/b2dpolypolygontools.hxx> |
| #include <basegfx/matrix/b2dhommatrix.hxx> |
| #include <canvas/canvastools.hxx> |
| |
| #include <boost/utility.hpp> |
| |
| #include "cachedprimitivebase.hxx" |
| #include "polypolyaction.hxx" |
| #include "outdevstate.hxx" |
| #include "mtftools.hxx" |
| |
| |
| using namespace ::com::sun::star; |
| |
| namespace cppcanvas |
| { |
| namespace internal |
| { |
| namespace |
| { |
| class PolyPolyAction : public CachedPrimitiveBase |
| { |
| public: |
| PolyPolyAction( const ::basegfx::B2DPolyPolygon&, |
| const CanvasSharedPtr&, |
| const OutDevState&, |
| bool bFill, |
| bool bStroke ); |
| PolyPolyAction( const ::basegfx::B2DPolyPolygon&, |
| const CanvasSharedPtr&, |
| const OutDevState&, |
| bool bFill, |
| bool bStroke, |
| int nTransparency ); |
| |
| virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const; |
| |
| virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; |
| virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const; |
| |
| virtual sal_Int32 getActionCount() const; |
| |
| private: |
| using Action::render; |
| virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, |
| const ::basegfx::B2DHomMatrix& rTransformation ) const; |
| |
| const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly; |
| const ::basegfx::B2DRange maBounds; |
| const CanvasSharedPtr mpCanvas; |
| |
| // stroke color is now implicit: the maState.DeviceColor member |
| rendering::RenderState maState; |
| |
| uno::Sequence< double > maFillColor; |
| }; |
| |
| PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, |
| const CanvasSharedPtr& rCanvas, |
| const OutDevState& rState, |
| bool bFill, |
| bool bStroke ) : |
| CachedPrimitiveBase( rCanvas, false ), |
| mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), |
| maBounds( ::basegfx::tools::getRange(rPolyPoly) ), |
| mpCanvas( rCanvas ), |
| maState(), |
| maFillColor() |
| { |
| tools::initRenderState(maState,rState); |
| |
| if( bFill ) |
| maFillColor = rState.fillColor; |
| |
| if( bStroke ) |
| maState.DeviceColor = rState.lineColor; |
| } |
| |
| PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, |
| const CanvasSharedPtr& rCanvas, |
| const OutDevState& rState, |
| bool bFill, |
| bool bStroke, |
| int nTransparency ) : |
| CachedPrimitiveBase( rCanvas, false ), |
| mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), |
| maBounds( ::basegfx::tools::getRange(rPolyPoly) ), |
| mpCanvas( rCanvas ), |
| maState(), |
| maFillColor() |
| { |
| tools::initRenderState(maState,rState); |
| |
| if( bFill ) |
| { |
| maFillColor = rState.fillColor; |
| |
| if( maFillColor.getLength() < 4 ) |
| maFillColor.realloc( 4 ); |
| |
| // TODO(F1): Color management |
| // adapt fill color transparency |
| maFillColor[3] = 1.0 - nTransparency / 100.0; |
| } |
| |
| if( bStroke ) |
| { |
| maState.DeviceColor = rState.lineColor; |
| |
| if( maState.DeviceColor.getLength() < 4 ) |
| maState.DeviceColor.realloc( 4 ); |
| |
| // TODO(F1): Color management |
| // adapt fill color transparency |
| maState.DeviceColor[3] = 1.0 - nTransparency / 100.0; |
| } |
| } |
| |
| bool PolyPolyAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, |
| const ::basegfx::B2DHomMatrix& rTransformation ) const |
| { |
| RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PolyPolyAction::render()" ); |
| RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PolyPolyAction: 0x%X", this ); |
| |
| rendering::RenderState aLocalState( maState ); |
| ::canvas::tools::prependToRenderState(aLocalState, rTransformation); |
| |
| #ifdef SPECIAL_DEBUG |
| aLocalState.Clip.clear(); |
| aLocalState.DeviceColor = |
| ::vcl::unotools::colorToDoubleSequence( mpCanvas->getUNOCanvas()->getDevice(), |
| ::Color( 0x80FF0000 ) ); |
| |
| if( maState.Clip.is() ) |
| mpCanvas->getUNOCanvas()->fillPolyPolygon( maState.Clip, |
| mpCanvas->getViewState(), |
| aLocalState ); |
| |
| aLocalState.DeviceColor = maState.DeviceColor; |
| #endif |
| |
| if( maFillColor.getLength() ) |
| { |
| // TODO(E3): Use DBO's finalizer here, |
| // fillPolyPolygon() might throw |
| const uno::Sequence< double > aTmpColor( aLocalState.DeviceColor ); |
| aLocalState.DeviceColor = maFillColor; |
| |
| rCachedPrimitive = mpCanvas->getUNOCanvas()->fillPolyPolygon( mxPolyPoly, |
| mpCanvas->getViewState(), |
| aLocalState ); |
| |
| aLocalState.DeviceColor = aTmpColor; |
| } |
| |
| if( aLocalState.DeviceColor.getLength() ) |
| { |
| rCachedPrimitive = mpCanvas->getUNOCanvas()->drawPolyPolygon( mxPolyPoly, |
| mpCanvas->getViewState(), |
| aLocalState ); |
| } |
| |
| return true; |
| } |
| |
| bool PolyPolyAction::render( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const |
| { |
| // TODO(F1): Split up poly-polygon into polygons, or even |
| // line segments, when subsets are requested. |
| |
| // polygon only contains a single action, fail if subset |
| // requests different range |
| if( rSubset.mnSubsetBegin != 0 || |
| rSubset.mnSubsetEnd != 1 ) |
| return false; |
| |
| return CachedPrimitiveBase::render( rTransformation ); |
| } |
| |
| ::basegfx::B2DRange PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const |
| { |
| rendering::RenderState aLocalState( maState ); |
| ::canvas::tools::prependToRenderState(aLocalState, rTransformation); |
| |
| return tools::calcDevicePixelBounds( |
| maBounds, |
| mpCanvas->getViewState(), |
| aLocalState ); |
| } |
| |
| ::basegfx::B2DRange PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const |
| { |
| // TODO(F1): Split up poly-polygon into polygons, or even |
| // line segments, when subsets are requested. |
| |
| // polygon only contains a single action, empty bounds |
| // if subset requests different range |
| if( rSubset.mnSubsetBegin != 0 || |
| rSubset.mnSubsetEnd != 1 ) |
| return ::basegfx::B2DRange(); |
| |
| return getBounds( rTransformation ); |
| } |
| |
| sal_Int32 PolyPolyAction::getActionCount() const |
| { |
| // TODO(F1): Split up poly-polygon into polygons, or even |
| // line segments, when subsets are requested. |
| return 1; |
| } |
| |
| |
| // ------------------------------------------------------------------------------- |
| |
| class TexturedPolyPolyAction : public CachedPrimitiveBase |
| { |
| public: |
| TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, |
| const CanvasSharedPtr& rCanvas, |
| const OutDevState& rState, |
| const rendering::Texture& rTexture ); |
| |
| virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const; |
| |
| virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; |
| virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const; |
| |
| virtual sal_Int32 getActionCount() const; |
| |
| private: |
| using Action::render; |
| virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, |
| const ::basegfx::B2DHomMatrix& rTransformation ) const; |
| |
| const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly; |
| const ::basegfx::B2DRectangle maBounds; |
| const CanvasSharedPtr mpCanvas; |
| |
| // stroke color is now implicit: the maState.DeviceColor member |
| rendering::RenderState maState; |
| const rendering::Texture maTexture; |
| }; |
| |
| TexturedPolyPolyAction::TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, |
| const CanvasSharedPtr& rCanvas, |
| const OutDevState& rState, |
| const rendering::Texture& rTexture ) : |
| CachedPrimitiveBase( rCanvas, true ), |
| mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), |
| maBounds( ::basegfx::tools::getRange(rPolyPoly) ), |
| mpCanvas( rCanvas ), |
| maState(), |
| maTexture( rTexture ) |
| { |
| tools::initRenderState(maState,rState); |
| } |
| |
| bool TexturedPolyPolyAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, |
| const ::basegfx::B2DHomMatrix& rTransformation ) const |
| { |
| RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PolyPolyAction::render()" ); |
| RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PolyPolyAction: 0x%X", this ); |
| |
| rendering::RenderState aLocalState( maState ); |
| ::canvas::tools::prependToRenderState(aLocalState, rTransformation); |
| |
| uno::Sequence< rendering::Texture > aSeq(1); |
| aSeq[0] = maTexture; |
| |
| rCachedPrimitive = mpCanvas->getUNOCanvas()->fillTexturedPolyPolygon( mxPolyPoly, |
| mpCanvas->getViewState(), |
| aLocalState, |
| aSeq ); |
| return true; |
| } |
| |
| bool TexturedPolyPolyAction::render( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const |
| { |
| // TODO(F1): Split up poly-polygon into polygons, or even |
| // line segments, when subsets are requested. |
| |
| // polygon only contains a single action, fail if subset |
| // requests different range |
| if( rSubset.mnSubsetBegin != 0 || |
| rSubset.mnSubsetEnd != 1 ) |
| return false; |
| |
| return CachedPrimitiveBase::render( rTransformation ); |
| } |
| |
| ::basegfx::B2DRange TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const |
| { |
| rendering::RenderState aLocalState( maState ); |
| ::canvas::tools::prependToRenderState(aLocalState, rTransformation); |
| |
| return tools::calcDevicePixelBounds( |
| maBounds, |
| mpCanvas->getViewState(), |
| aLocalState ); |
| } |
| |
| ::basegfx::B2DRange TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const |
| { |
| // TODO(F1): Split up poly-polygon into polygons, or even |
| // line segments, when subsets are requested. |
| |
| // polygon only contains a single action, empty bounds |
| // if subset requests different range |
| if( rSubset.mnSubsetBegin != 0 || |
| rSubset.mnSubsetEnd != 1 ) |
| return ::basegfx::B2DRange(); |
| |
| return getBounds( rTransformation ); |
| } |
| |
| sal_Int32 TexturedPolyPolyAction::getActionCount() const |
| { |
| // TODO(F1): Split up poly-polygon into polygons, or even |
| // line segments, when subsets are requested. |
| return 1; |
| } |
| |
| // ------------------------------------------------------------------------------- |
| |
| class StrokedPolyPolyAction : public CachedPrimitiveBase |
| { |
| public: |
| StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, |
| const CanvasSharedPtr& rCanvas, |
| const OutDevState& rState, |
| const rendering::StrokeAttributes& rStrokeAttributes ); |
| |
| virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const; |
| |
| virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const; |
| virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const; |
| |
| virtual sal_Int32 getActionCount() const; |
| |
| private: |
| using Action::render; |
| virtual bool render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, |
| const ::basegfx::B2DHomMatrix& rTransformation ) const; |
| |
| const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly; |
| const ::basegfx::B2DRectangle maBounds; |
| const CanvasSharedPtr mpCanvas; |
| rendering::RenderState maState; |
| const rendering::StrokeAttributes maStrokeAttributes; |
| }; |
| |
| StrokedPolyPolyAction::StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly, |
| const CanvasSharedPtr& rCanvas, |
| const OutDevState& rState, |
| const rendering::StrokeAttributes& rStrokeAttributes ) : |
| CachedPrimitiveBase( rCanvas, false ), |
| mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ), |
| maBounds( ::basegfx::tools::getRange(rPolyPoly) ), |
| mpCanvas( rCanvas ), |
| maState(), |
| maStrokeAttributes( rStrokeAttributes ) |
| { |
| tools::initRenderState(maState,rState); |
| maState.DeviceColor = rState.lineColor; |
| } |
| |
| bool StrokedPolyPolyAction::render( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive, |
| const ::basegfx::B2DHomMatrix& rTransformation ) const |
| { |
| RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::PolyPolyAction::render()" ); |
| RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::PolyPolyAction: 0x%X", this ); |
| |
| rendering::RenderState aLocalState( maState ); |
| ::canvas::tools::prependToRenderState(aLocalState, rTransformation); |
| |
| rCachedPrimitive = mpCanvas->getUNOCanvas()->strokePolyPolygon( mxPolyPoly, |
| mpCanvas->getViewState(), |
| aLocalState, |
| maStrokeAttributes ); |
| return true; |
| } |
| |
| bool StrokedPolyPolyAction::render( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const |
| { |
| // TODO(F1): Split up poly-polygon into polygons, or even |
| // line segments, when subsets are requested. |
| |
| // polygon only contains a single action, fail if subset |
| // requests different range |
| if( rSubset.mnSubsetBegin != 0 || |
| rSubset.mnSubsetEnd != 1 ) |
| return false; |
| |
| return CachedPrimitiveBase::render( rTransformation ); |
| } |
| |
| ::basegfx::B2DRange StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const |
| { |
| rendering::RenderState aLocalState( maState ); |
| ::canvas::tools::prependToRenderState(aLocalState, rTransformation); |
| |
| return tools::calcDevicePixelBounds( |
| maBounds, |
| mpCanvas->getViewState(), |
| aLocalState ); |
| } |
| |
| ::basegfx::B2DRange StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation, |
| const Subset& rSubset ) const |
| { |
| // TODO(F1): Split up poly-polygon into polygons, or even |
| // line segments, when subsets are requested. |
| |
| // polygon only contains a single action, empty bounds |
| // if subset requests different range |
| if( rSubset.mnSubsetBegin != 0 || |
| rSubset.mnSubsetEnd != 1 ) |
| return ::basegfx::B2DRange(); |
| |
| return getBounds( rTransformation ); |
| } |
| |
| sal_Int32 StrokedPolyPolyAction::getActionCount() const |
| { |
| // TODO(F1): Split up poly-polygon into polygons, or even |
| // line segments, when subsets are requested. |
| return 1; |
| } |
| } |
| |
| ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, |
| const CanvasSharedPtr& rCanvas, |
| const OutDevState& rState ) |
| { |
| OSL_ENSURE( rState.isLineColorSet || rState.isFillColorSet, |
| "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" ); |
| return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState, |
| rState.isFillColorSet, |
| rState.isLineColorSet ) ); |
| } |
| |
| ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, |
| const CanvasSharedPtr& rCanvas, |
| const OutDevState& rState, |
| const rendering::Texture& rTexture ) |
| { |
| return ActionSharedPtr( new TexturedPolyPolyAction( rPoly, rCanvas, rState, rTexture ) ); |
| } |
| |
| ActionSharedPtr PolyPolyActionFactory::createLinePolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, |
| const CanvasSharedPtr& rCanvas, |
| const OutDevState& rState ) |
| { |
| OSL_ENSURE( rState.isLineColorSet, |
| "PolyPolyActionFactory::createLinePolyPolyAction() called with empty line color" ); |
| |
| return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState, |
| false, |
| rState.isLineColorSet ) ); |
| } |
| |
| ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, |
| const CanvasSharedPtr& rCanvas, |
| const OutDevState& rState, |
| const rendering::StrokeAttributes& rStrokeAttributes ) |
| { |
| OSL_ENSURE( rState.isLineColorSet, |
| "PolyPolyActionFactory::createPolyPolyAction() for strokes called with empty line color" ); |
| return ActionSharedPtr( new StrokedPolyPolyAction( rPoly, rCanvas, rState, rStrokeAttributes ) ); |
| } |
| |
| ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly, |
| const CanvasSharedPtr& rCanvas, |
| const OutDevState& rState, |
| int nTransparency ) |
| { |
| OSL_ENSURE( rState.isLineColorSet || rState.isFillColorSet, |
| "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" ); |
| return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState, |
| rState.isFillColorSet, |
| rState.isLineColorSet, |
| nTransparency ) ); |
| } |
| |
| } |
| } |