diff options
author | Armin Le Grand <alg@apache.org> | 2012-10-16 08:44:02 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2013-06-11 20:00:34 +0100 |
commit | 37aa7d81aacaae12dfe0fd2ade2779235bbf72f1 (patch) | |
tree | baf84cf5f8fcf62221dd75869d507d2396ae690b /drawinglayer/source/processor2d | |
parent | e72e1c110ad42b779afbe74b47ca35c1849e06b2 (diff) |
Resolves: #i121194# Better support for graphic fill styles...
which are not bitmaps (svg, metafiles, ..)
(cherry picked from commit 7a652a2b2ab5e0d37e32185c8c5fac3af482bb76)
Conflicts:
drawinglayer/Library_drawinglayer.mk
drawinglayer/Package_inc.mk
drawinglayer/inc/drawinglayer/attribute/fillgraphicattribute.hxx
drawinglayer/inc/drawinglayer/attribute/sdrfillattribute.hxx
drawinglayer/inc/drawinglayer/attribute/sdrfillgraphicattribute.hxx
drawinglayer/inc/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx
drawinglayer/inc/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx
drawinglayer/inc/drawinglayer/primitive2d/polypolygonprimitive2d.hxx
drawinglayer/inc/drawinglayer/primitive3d/textureprimitive3d.hxx
drawinglayer/inc/drawinglayer/processor2d/vclprocessor2d.hxx
drawinglayer/inc/drawinglayer/texture/texture.hxx
drawinglayer/inc/drawinglayer/texture/texture3d.hxx
drawinglayer/source/attribute/fillbitmapattribute.cxx
drawinglayer/source/attribute/sdrfillattribute.cxx
drawinglayer/source/attribute/sdrfillgraphicattribute.cxx
drawinglayer/source/primitive2d/fillbitmapprimitive2d.cxx
drawinglayer/source/primitive2d/graphicprimitive2d.cxx
drawinglayer/source/primitive2d/polypolygonprimitive2d.cxx
drawinglayer/source/processor2d/canvasprocessor.cxx
svx/inc/svx/sdr/primitive2d/sdrattributecreator.hxx
svx/source/sdr/contact/objectcontacttools.cxx
vcl/inc/vcl/graph.hxx
unused file _vclmetafileprocessor2d.cxx deleted, was added by error
(cherry picked from commit ed0d53f8283cd3ce579a90b599118884d0db6119)
Conflicts:
drawinglayer/source/processor2d/_vclmetafileprocessor2d.cxx
Corrected canvasProcessor usage
(cherry picked from commit 7903c33f31c457eb6ff506958c4233f2a5d39bcf)
Conflicts:
svx/source/sdr/contact/objectcontacttools.cxx
Change-Id: I80008050b98dafc92fde043524843c13a75fe22c
d2fa667d7c127b4d735334e56093d1d4553b0a5b
e20c60c7d6472da1295a162d9a629be998861f62
Diffstat (limited to 'drawinglayer/source/processor2d')
5 files changed, 279 insertions, 1222 deletions
diff --git a/drawinglayer/source/processor2d/canvasprocessor.cxx b/drawinglayer/source/processor2d/canvasprocessor.cxx deleted file mode 100644 index b8d260aa941e..000000000000 --- a/drawinglayer/source/processor2d/canvasprocessor.cxx +++ /dev/null @@ -1,993 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <drawinglayer/processor2d/canvasprocessor.hxx> -#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> -#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> -#include <com/sun/star/rendering/XCanvas.hpp> -#include <vcl/canvastools.hxx> -#include <basegfx/tools/canvastools.hxx> -#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> -#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> -#include <drawinglayer/primitive2d/transformprimitive2d.hxx> -#include <canvas/canvastools.hxx> -#include <drawinglayer/primitive2d/maskprimitive2d.hxx> -#include <basegfx/polygon/b2dpolygonclipper.hxx> -#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx> -#include <drawinglayer/primitive2d/metafileprimitive2d.hxx> -#include <cppcanvas/basegfxfactory.hxx> -#include <com/sun/star/rendering/XBitmapCanvas.hpp> -#include <cppcanvas/vclfactory.hxx> -#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx> -#include <drawinglayer/primitive2d/textprimitive2d.hxx> -#include <com/sun/star/rendering/TextDirection.hpp> -#include <vclhelperbitmaptransform.hxx> -#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> -#include <basegfx/polygon/b2dpolygontools.hxx> -#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx> -#include <basegfx/tuple/b2i64tuple.hxx> -#include <basegfx/range/b2irange.hxx> -#include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp> -#include <com/sun/star/rendering/PanoseProportion.hpp> -#include <com/sun/star/rendering/CompositeOperation.hpp> -#include <com/sun/star/rendering/StrokeAttributes.hpp> -#include <com/sun/star/rendering/PathJoinType.hpp> -#include <com/sun/star/rendering/PathCapType.hpp> -#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> -#include <com/sun/star/rendering/TexturingMode.hpp> -#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> -#include <vclhelperbufferdevice.hxx> -#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx> -#include <helperwrongspellrenderer.hxx> -#include <basegfx/matrix/b2dhommatrixtools.hxx> - -#include "getdigitlanguage.hxx" - -////////////////////////////////////////////////////////////////////////////// - -using namespace com::sun::star; - -////////////////////////////////////////////////////////////////////////////// - -namespace drawinglayer -{ - namespace processor2d - { - ////////////////////////////////////////////////////////////////////////////// - // single primitive renderers - - void canvasProcessor2D::impRenderMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate) - { - const primitive2d::Primitive2DSequence& rChildren = rMaskCandidate.getChildren(); - static bool bUseMaskBitmapMethod(true); - - if(rChildren.hasElements()) - { - basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); - - if(!aMask.count()) - { - // no mask, no clipping. recursively paint content - process(rChildren); - } - else - { - // there are principally two methods for implementing the mask primitive. One - // is to set a clip polygon at the canvas, the other is to create and use a - // transparence-using XBitmap for content and draw the mask as transparence. Both have their - // advantages and disadvantages, so here are both with a bool allowing simple - // change - if(bUseMaskBitmapMethod) - { - // get logic range of transparent part, clip with ViewRange - basegfx::B2DRange aLogicRange(aMask.getB2DRange()); - - if(!getViewInformation2D().getViewport().isEmpty()) - { - aLogicRange.intersect(getViewInformation2D().getViewport()); - } - - if(!aLogicRange.isEmpty()) - { - // get discrete range of transparent part - basegfx::B2DRange aDiscreteRange(aLogicRange); - aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation()); - - // expand to next covering discrete values (pixel bounds) - aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY()))); - aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY()))); - - // use VCL-based buffer device - impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false); - - if(aBufferDevice.isVisible()) - { - // remember current OutDev, Canvas and ViewInformation - OutputDevice* pLastOutputDevice = mpOutputDevice; - uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas); - const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); - - // prepare discrete offset for XBitmap, do not forget that the buffer bitmap - // may be truncated to discrete visible pixels - const basegfx::B2DHomMatrix aDiscreteOffset(basegfx::tools::createTranslateB2DHomMatrix( - aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0, - aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0)); - - // create new local ViewInformation2D with new transformation - const geometry::ViewInformation2D aViewInformation2D( - getViewInformation2D().getObjectTransformation(), - aDiscreteOffset * getViewInformation2D().getViewTransformation(), - getViewInformation2D().getViewport(), - getViewInformation2D().getVisualizedPage(), - getViewInformation2D().getViewTime(), - getViewInformation2D().getExtendedInformationSequence()); - updateViewInformation(aViewInformation2D); - - // set OutDev and Canvas to content target - mpOutputDevice = &aBufferDevice.getContent(); - mxCanvas = mpOutputDevice->GetCanvas(); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // if ViewState transform is changed, the clipping polygon needs to be adapted, too - const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon); - - if(maClipPolyPolygon.count()) - { - maClipPolyPolygon.transform(aDiscreteOffset); - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - - // paint content - process(rChildren); - - // draw mask - const basegfx::BColor aBlack(0.0, 0.0, 0.0); - maRenderState.DeviceColor = aBlack.colorToDoubleSequence(mxCanvas->getDevice()); - - if(getOptionsDrawinglayer().IsAntiAliasing()) - { - // with AA, use 8bit AlphaMask to get nice borders - VirtualDevice& rTransparence = aBufferDevice.getTransparence(); - rTransparence.GetCanvas()->fillPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask), - maViewState, maRenderState); - } - else - { - // No AA, use 1bit mask - VirtualDevice& rMask = aBufferDevice.getMask(); - rMask.GetCanvas()->fillPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask), - maViewState, maRenderState); - } - - // back to old color stack, OutDev, Canvas and ViewTransform - mpOutputDevice = pLastOutputDevice; - mxCanvas = xLastCanvas; - updateViewInformation(aLastViewInformation2D); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // restore clipping polygon - maClipPolyPolygon = aOldClipPolyPolygon; - - if(maClipPolyPolygon.count()) - { - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - - // dump buffer to outdev - aBufferDevice.paint(); - } - } - } - else - { - // transform new mask polygon to view coordinates for processing. All masks - // are processed in view coordinates and clipped against each other evtl. to - // create multi-clips - aMask.transform(getViewInformation2D().getObjectTransformation()); - - // remember last current clip polygon - const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon); - - if(maClipPolyPolygon.count()) - { - // there is already a clip polygon set; build clipped union of - // current mask polygon and new one - maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(aMask, maClipPolyPolygon, false, false); - } - else - { - // use mask directly - maClipPolyPolygon = aMask; - } - - // set at ViewState - if(maClipPolyPolygon.count()) - { - // set new as clip polygon - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - else - { - // empty, reset - maViewState.Clip.clear(); - } - - // paint content - process(rChildren); - - // restore local current to rescued clip polygon - maClipPolyPolygon = aLastClipPolyPolygon; - - // set at ViewState - if(maClipPolyPolygon.count()) - { - // set new as clip polygon - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - else - { - // empty, reset - maViewState.Clip.clear(); - } - } - } - } - } - - void canvasProcessor2D::impRenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate) - { - GDIMetaFile aMetaFile; - - if(maBColorModifierStack.count()) - { - const basegfx::BColor aRGBBaseColor(0, 0, 0); - const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor)); - aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor)); - } - else - { - aMetaFile = rMetaCandidate.getMetaFile(); - } - - cppcanvas::BitmapCanvasSharedPtr pCanvas(cppcanvas::VCLFactory::getInstance().createCanvas( - uno::Reference<rendering::XBitmapCanvas>(mxCanvas, uno::UNO_QUERY_THROW))); - cppcanvas::RendererSharedPtr pMtfRenderer(cppcanvas::VCLFactory::getInstance().createRenderer( - pCanvas, aMetaFile, cppcanvas::Renderer::Parameters())); - - if(pMtfRenderer) - { - pCanvas->setTransformation(getViewInformation2D().getObjectToViewTransformation()); - pMtfRenderer->setTransformation(rMetaCandidate.getTransform()); - pMtfRenderer->draw(); - } - } - - void canvasProcessor2D::impRenderTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate) - { - if(rTextCandidate.getTextLength()) - { - double fShearX(0.0); - { - const basegfx::B2DHomMatrix aLocalTransform(getViewInformation2D().getObjectToViewTransformation() * rTextCandidate.getTextTransform()); - basegfx::B2DVector aScale, aTranslate; - double fRotate; - aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); - } - - if(!basegfx::fTools::equalZero(fShearX)) - { - // text is sheared. As long as the canvas renderers do not support this, - // use the decomposed primitive - process(rTextCandidate.get2DDecomposition(getViewInformation2D())); - } - else - { - const attribute::FontAttribute& rFontAttr(rTextCandidate.getFontAttribute()); - rendering::FontRequest aFontRequest; - - aFontRequest.FontDescription.FamilyName = rFontAttr.getFamilyName(); - aFontRequest.FontDescription.StyleName = rFontAttr.getStyleName(); - aFontRequest.FontDescription.IsSymbolFont = rFontAttr.getSymbol() ? util::TriState_YES : util::TriState_NO; - aFontRequest.FontDescription.IsVertical = rFontAttr.getVertical() ? util::TriState_YES : util::TriState_NO; - // TODO(F2): improve vclenum->panose conversion - aFontRequest.FontDescription.FontDescription.Weight = static_cast< sal_uInt8 >(rFontAttr.getWeight()); - aFontRequest.FontDescription.FontDescription.Proportion = - rFontAttr.getMonospaced() - ? rendering::PanoseProportion::MONO_SPACED - : rendering::PanoseProportion::ANYTHING; - aFontRequest.FontDescription.FontDescription.Letterform = rFontAttr.getItalic() ? 9 : 0; - - // init CellSize to 1.0, else a default font height will be used - aFontRequest.CellSize = 1.0; - aFontRequest.Locale = rTextCandidate.getLocale(); - - // font matrix should only be used for glyph rotations etc. - com::sun::star::geometry::Matrix2D aFontMatrix; - canvas::tools::setIdentityMatrix2D(aFontMatrix); - - uno::Reference<rendering::XCanvasFont> xFont(mxCanvas->createFont( - aFontRequest, uno::Sequence< beans::PropertyValue >(), aFontMatrix)); - - if(xFont.is()) - { - // got a font, now try to get a TextLayout - const rendering::StringContext aStringContext( - rTextCandidate.getText(), rTextCandidate.getTextPosition(), rTextCandidate.getTextLength()); - uno::Reference<rendering::XTextLayout> xLayout(xFont->createTextLayout( - aStringContext, com::sun::star::rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0)); - - if(xLayout.is()) - { - // got a text layout, apply DXArray if given - const ::std::vector< double >& rDXArray = rTextCandidate.getDXArray(); - const sal_uInt32 nDXCount(rDXArray.size()); - - if(nDXCount) - { - // DXArray does not need to be adapted to getTextPosition/getTextLength, - // it is already provided correctly - const uno::Sequence< double > aDXSequence(&rDXArray[0], nDXCount); - xLayout->applyLogicalAdvancements(aDXSequence); - } - - // set text color - const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor())); - maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice()); - - // set text transformation - canvas::tools::setRenderStateTransform(maRenderState, - getViewInformation2D().getObjectTransformation() * rTextCandidate.getTextTransform()); - - // paint - mxCanvas->drawTextLayout(xLayout, maViewState, maRenderState); - } - } - } - } - } - - void canvasProcessor2D::impRenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate) - { - // apply possible color modification to BitmapEx - BitmapEx aModifiedBitmapEx(impModifyBitmapEx(maBColorModifierStack, rBitmapCandidate.getBitmapEx())); - - if(aModifiedBitmapEx.IsEmpty()) - { - // replace with color filled polygon - const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); - const basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); - - maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, - getViewInformation2D().getObjectTransformation() * rBitmapCandidate.getTransform()); - - mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState); - } - else - { - // adapt object's transformation to the correct scale - basegfx::B2DVector aScale, aTranslate; - const Size aSizePixel(aModifiedBitmapEx.GetSizePixel()); - - if(0 != aSizePixel.Width() && 0 != aSizePixel.Height()) - { - double fRotate, fShearX; - rBitmapCandidate.getTransform().decompose(aScale, aTranslate, fRotate, fShearX); - const basegfx::B2DHomMatrix aNewMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( - aScale.getX() / aSizePixel.Width(), aScale.getY() / aSizePixel.Height(), - fShearX, fRotate, aTranslate.getX(), aTranslate.getY())); - - canvas::tools::setRenderStateTransform(maRenderState, - getViewInformation2D().getObjectTransformation() * aNewMatrix); - - mxCanvas->drawBitmap( - vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aModifiedBitmapEx), - maViewState, maRenderState); - } - } - } - - void canvasProcessor2D::impRenderTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransparenceCandidate) - { - const primitive2d::Primitive2DSequence& rChildren = rTransparenceCandidate.getChildren(); - const primitive2d::Primitive2DSequence& rTransparence = rTransparenceCandidate.getTransparence(); - - if(rChildren.hasElements() && rTransparence.hasElements()) - { - // get logic range of transparent part and clip with ViewRange - basegfx::B2DRange aLogicRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rChildren, getViewInformation2D())); - - if(!getViewInformation2D().getViewport().isEmpty()) - { - aLogicRange.intersect(getViewInformation2D().getViewport()); - } - - if(!aLogicRange.isEmpty()) - { - // get discrete range of transparent part - basegfx::B2DRange aDiscreteRange(aLogicRange); - aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation()); - - // expand to next covering discrete values (pixel bounds) - aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY()))); - aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY()))); - - // use VCL-based buffer device - impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false); - - if(aBufferDevice.isVisible()) - { - // remember current OutDev, Canvas and ViewInformation - OutputDevice* pLastOutputDevice = mpOutputDevice; - uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas); - const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); - - // prepare discrete offset for XBitmap, do not forget that the buffer bitmap - // may be truncated to discrete visible pixels - const basegfx::B2DHomMatrix aDiscreteOffset(basegfx::tools::createTranslateB2DHomMatrix( - aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0, - aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0)); - - // create new local ViewInformation2D with new transformation - const geometry::ViewInformation2D aViewInformation2D( - getViewInformation2D().getObjectTransformation(), - aDiscreteOffset * getViewInformation2D().getViewTransformation(), - getViewInformation2D().getViewport(), - getViewInformation2D().getVisualizedPage(), - getViewInformation2D().getViewTime(), - getViewInformation2D().getExtendedInformationSequence()); - updateViewInformation(aViewInformation2D); - - // set OutDev and Canvas to content target - mpOutputDevice = &aBufferDevice.getContent(); - mxCanvas = mpOutputDevice->GetCanvas(); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // if ViewState transform is changed, the clipping polygon needs to be adapted, too - const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon); - - if(maClipPolyPolygon.count()) - { - maClipPolyPolygon.transform(aDiscreteOffset); - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - - // paint content - process(rChildren); - - // set to mask - mpOutputDevice = &aBufferDevice.getTransparence(); - mxCanvas = mpOutputDevice->GetCanvas(); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // when painting transparence masks, reset the color stack - basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack); - maBColorModifierStack = basegfx::BColorModifierStack(); - - // paint mask to it (always with transparence intensities, evtl. with AA) - process(rTransparence); - - // back to old color stack, OutDev, Canvas and ViewTransform - maBColorModifierStack = aLastBColorModifierStack; - mpOutputDevice = pLastOutputDevice; - mxCanvas = xLastCanvas; - updateViewInformation(aLastViewInformation2D); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // restore clipping polygon - maClipPolyPolygon = aOldClipPolyPolygon; - - if(maClipPolyPolygon.count()) - { - maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon); - } - - // dump buffer to outdev - aBufferDevice.paint(); - } - } - } - } - - void canvasProcessor2D::impRenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive) - { - // support direct fat line geometry. This moves the decomposition to the canvas. - // As long as our canvases are used (which also use basegfx tooling) this makes - // no difference, but potentially canvases may better support this - static bool bSupportFatLineDirectly(true); - bool bOutputDone(false); - - if(bSupportFatLineDirectly) - { - const attribute::LineAttribute& rLineAttribute = rPolygonStrokePrimitive.getLineAttribute(); - const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokePrimitive.getStrokeAttribute(); - - if(0.0 < rLineAttribute.getWidth() || 0 != rStrokeAttribute.getDotDashArray().size()) - { - rendering::StrokeAttributes aStrokeAttribute; - - aStrokeAttribute.StrokeWidth = rLineAttribute.getWidth(); - aStrokeAttribute.MiterLimit = 15.0; // degrees; maybe here (15.0 * F_PI180) is needed, not clear in the documentation - const ::std::vector< double >& rDotDashArray = rStrokeAttribute.getDotDashArray(); - - if(!rDotDashArray.empty()) - { - aStrokeAttribute.DashArray = uno::Sequence< double >(&rDotDashArray[0], rDotDashArray.size()); - } - - switch(rLineAttribute.getLineJoin()) - { - default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE - aStrokeAttribute.JoinType = rendering::PathJoinType::NONE; - break; - case basegfx::B2DLINEJOIN_BEVEL: - aStrokeAttribute.JoinType = rendering::PathJoinType::BEVEL; - break; - case basegfx::B2DLINEJOIN_MITER: - aStrokeAttribute.JoinType = rendering::PathJoinType::MITER; - break; - case basegfx::B2DLINEJOIN_ROUND: - aStrokeAttribute.JoinType = rendering::PathJoinType::ROUND; - break; - } - - switch(rLineAttribute.getLineCap()) - { - case com::sun::star::drawing::LineCap_ROUND: - aStrokeAttribute.StartCapType = rendering::PathCapType::ROUND; - aStrokeAttribute.EndCapType = rendering::PathCapType::ROUND; - break; - case com::sun::star::drawing::LineCap_SQUARE: - aStrokeAttribute.StartCapType = rendering::PathCapType::SQUARE; - aStrokeAttribute.EndCapType = rendering::PathCapType::SQUARE; - break; - default: // com::sun::star::drawing::LineCap_BUTT - aStrokeAttribute.StartCapType = rendering::PathCapType::BUTT; - aStrokeAttribute.EndCapType = rendering::PathCapType::BUTT; - break; - } - - const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor())); - maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - - mxCanvas->strokePolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonStrokePrimitive.getB2DPolygon()), - maViewState, maRenderState, aStrokeAttribute); - - bOutputDone = true; - } - } - - if(!bOutputDone) - { - // process decomposition - process(rPolygonStrokePrimitive.get2DDecomposition(getViewInformation2D())); - } - } - - void canvasProcessor2D::impRenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapPrimitive2D) - { - // support tiled fills directly when tiling is on - static bool bSupportFillBitmapDirectly(true); - bool bOutputDone(false); - - if(bSupportFillBitmapDirectly) - { - const attribute::FillBitmapAttribute& rFillBitmapAttribute = rFillBitmapPrimitive2D.getFillBitmap(); - - if(rFillBitmapAttribute.getTiling()) - { - // apply possible color modification to Bitmap - const BitmapEx aChangedBitmapEx(impModifyBitmapEx(maBColorModifierStack, rFillBitmapAttribute.getBitmapEx())); - - if(aChangedBitmapEx.IsEmpty()) - { - // replace with color filled polygon - const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); - const basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); - - maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, - getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation()); - - mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( - mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState); - } - else - { - const Size aSizePixel(aChangedBitmapEx.GetSizePixel()); - - if(0 != aSizePixel.Width() && 0 != aSizePixel.Height()) - { - // create texture matrix from texture to object (where object is unit square here), - // so use values directly - const basegfx::B2DHomMatrix aTextureMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix( - rFillBitmapAttribute.getSize().getX(), rFillBitmapAttribute.getSize().getY(), - rFillBitmapAttribute.getTopLeft().getX(), rFillBitmapAttribute.getTopLeft().getY())); - - // create and fill texture - rendering::Texture aTexture; - - basegfx::unotools::affineMatrixFromHomMatrix(aTexture.AffineTransform, aTextureMatrix); - aTexture.Alpha = 1.0; - aTexture.Bitmap = vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aChangedBitmapEx); - aTexture.RepeatModeX = rendering::TexturingMode::REPEAT; - aTexture.RepeatModeY = rendering::TexturingMode::REPEAT; - - // canvas needs a polygon to fill, create unit rectangle polygon - const basegfx::B2DPolygon aOutlineRectangle(basegfx::tools::createUnitPolygon()); - - // set primitive's transformation as render state transform - canvas::tools::setRenderStateTransform(maRenderState, - getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation()); - - // put texture into a uno sequence for handover - uno::Sequence< rendering::Texture > aSeq(1); - aSeq[0] = aTexture; - - // draw textured rectangle - mxCanvas->fillTexturedPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aOutlineRectangle)), - maViewState, maRenderState, aSeq); - } - } - - bOutputDone = true; - } - } - - if(!bOutputDone) - { - // process decomposition - process(rFillBitmapPrimitive2D.get2DDecomposition(getViewInformation2D())); - } - } - - void canvasProcessor2D::impRenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate) - { - if(0.0 == rUniTransparenceCandidate.getTransparence()) - { - // not transparent at all, directly use content - process(rUniTransparenceCandidate.getChildren()); - } - else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0) - { - const primitive2d::Primitive2DSequence rChildren = rUniTransparenceCandidate.getChildren(); - - if(rChildren.hasElements()) - { - bool bOutputDone(false); - - // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case, - // use the fillPolyPolygon method with correctly set transparence. This is a often used - // case, so detectiong it is valuable - if(1 == rChildren.getLength()) - { - const primitive2d::Primitive2DReference xReference(rChildren[0]); - const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get()); - - if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID()) - { - // direct draw of PolyPolygon with color and transparence - const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); - - // add transparence modulation value to DeviceColor - uno::Sequence< double > aColor(4); - - aColor[0] = aPolygonColor.getRed(); - aColor[1] = aPolygonColor.getGreen(); - aColor[2] = aPolygonColor.getBlue(); - aColor[3] = 1.0 - rUniTransparenceCandidate.getTransparence(); - maRenderState.DeviceColor = aColor; - - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - mxCanvas->fillPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), pPoPoColor->getB2DPolyPolygon()), - maViewState, maRenderState); - bOutputDone = true; - } - } - - if(!bOutputDone) - { - // process decomposition. This will be decomposed to an TransparencePrimitive2D - // with the same child context and a single polygon for transparent context. This could be - // directly handled here with known VCL-buffer technology, but would only - // make a small difference compared to directly rendering the TransparencePrimitive2D - // using impRenderTransparencePrimitive2D above. - process(rUniTransparenceCandidate.get2DDecomposition(getViewInformation2D())); - } - } - } - } - - ////////////////////////////////////////////////////////////////////////////// - // internal processing support - - void canvasProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) - { - switch(rCandidate.getPrimitive2DID()) - { - case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : - { - // direct draw of hairline - const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate); - const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); - - maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - mxCanvas->drawPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolygon()), - maViewState, maRenderState); - - break; - } - case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : - { - // direct draw of PolyPolygon with color - const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate); - const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); - - maRenderState.DeviceColor = aPolygonColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - mxCanvas->fillPolyPolygon( - basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolyPolygon()), - maViewState, maRenderState); - - break; - } - case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D : - { - // modified color group. Force output to unified color. - const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate = static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate); - - if(rModifiedCandidate.getChildren().hasElements()) - { - maBColorModifierStack.push(rModifiedCandidate.getColorModifier()); - process(rModifiedCandidate.getChildren()); - maBColorModifierStack.pop(); - } - - break; - } - case PRIMITIVE2D_ID_MASKPRIMITIVE2D : - { - // mask group - impRenderMaskPrimitive2D(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : - { - // transform group. Remember current ViewInformation2D - const primitive2d::TransformPrimitive2D& rTransformCandidate = static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate); - const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); - - // create new local ViewInformation2D with new transformation - const geometry::ViewInformation2D aViewInformation2D( - getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(), - getViewInformation2D().getViewTransformation(), - getViewInformation2D().getViewport(), - getViewInformation2D().getVisualizedPage(), - getViewInformation2D().getViewTime(), - getViewInformation2D().getExtendedInformationSequence()); - updateViewInformation(aViewInformation2D); - - // set at canvas - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - - // proccess content - process(rTransformCandidate.getChildren()); - - // restore transformations - updateViewInformation(aLastViewInformation2D); - - // restore at canvas - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - - break; - } - case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : - { - // new XDrawPage for ViewInformation2D - const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate = static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate); - - // remember current transformation and ViewInformation - const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D()); - - // create new local ViewInformation2D - const geometry::ViewInformation2D aViewInformation2D( - getViewInformation2D().getObjectTransformation(), - getViewInformation2D().getViewTransformation(), - getViewInformation2D().getViewport(), - rPagePreviewCandidate.getXDrawPage(), - getViewInformation2D().getViewTime(), - getViewInformation2D().getExtendedInformationSequence()); - updateViewInformation(aViewInformation2D); - - // proccess decomposed content - process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D())); - - // restore transformations - updateViewInformation(aLastViewInformation2D); - break; - } - case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D : - { - // MetaFile primitive - impRenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : - { - // PointArray primitive - const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate = static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate); - - // set point color - const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor())); - maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice()); - canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation()); - - const std::vector< basegfx::B2DPoint >& rPointVector = rPointArrayCandidate.getPositions(); - const sal_uInt32 nPointCount(rPointVector.size()); - - for(sal_uInt32 a(0); a < nPointCount; a++) - { - const basegfx::B2DPoint& rPoint = rPointVector[a]; - mxCanvas->drawPoint(basegfx::unotools::point2DFromB2DPoint(rPoint), maViewState, maRenderState); - } - - break; - } - case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : - { - // TextSimplePortion primitive - impRenderTextSimplePortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : - { - // Bitmap primitive - impRenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D : - { - // Transparence primitive - impRenderTransparencePrimitive2D(static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D: - { - // PolygonStrokePrimitive - impRenderPolygonStrokePrimitive2D(static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D : - { - // FillBitmapPrimitive2D - impRenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D : - { - // UnifiedTransparencePrimitive2D - impRenderUnifiedTransparencePrimitive2D(static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate)); - - break; - } - case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D : - { - // wrong spell primitive. Handled directly here using VCL since VCL has a nice and - // very direct waveline painting which is needed for this. If VCL is to be avoided, - // this can be removed anytime and the decomposition may be used - const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive = static_cast< const primitive2d::WrongSpellPrimitive2D& >(rCandidate); - - if(!renderWrongSpellPrimitive2D( - rWrongSpellPrimitive, - *mpOutputDevice, - getViewInformation2D().getObjectToViewTransformation(), - maBColorModifierStack)) - { - // fallback to decomposition (MetaFile) - process(rWrongSpellPrimitive.get2DDecomposition(getViewInformation2D())); - } - - break; - } - - // nice to have: - // - // case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D : - // - support FormControls more direct eventually, not sure if this is needed - // with the canvas renderer. The decomposition provides a bitmap representation - // of the control which will work - // - - default : - { - // process recursively - process(rCandidate.get2DDecomposition(getViewInformation2D())); - - break; - } - } - } - - ////////////////////////////////////////////////////////////////////////////// - // process support - - canvasProcessor2D::canvasProcessor2D( - const geometry::ViewInformation2D& rViewInformation, - OutputDevice& rOutDev) - : BaseProcessor2D(rViewInformation), - mpOutputDevice(&rOutDev), - mxCanvas(rOutDev.GetCanvas()), - maViewState(), - maRenderState(), - maBColorModifierStack(), - maDrawinglayerOpt(), - maClipPolyPolygon(), - meLang(drawinglayer::detail::getDigitLanguage()) - { - canvas::tools::initViewState(maViewState); - canvas::tools::initRenderState(maRenderState); - canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation()); - - // set digit language, derived from SvtCTLOptions to have the correct - // number display for arabic/hindi numerals - rOutDev.SetDigitLanguage(meLang); - - // prepare output directly to pixels - mpOutputDevice->Push(PUSH_MAPMODE); - mpOutputDevice->SetMapMode(); - - // react on AntiAliasing settings - if(getOptionsDrawinglayer().IsAntiAliasing()) - { - mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW); - } - else - { - mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); - } - } - - canvasProcessor2D::~canvasProcessor2D() - { - // restore MapMode - mpOutputDevice->Pop(); - - // restore AntiAliasing - mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW); - } - } // end of namespace processor2d -} // end of namespace drawinglayer - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/drawinglayer/source/processor2d/processorfromoutputdevice.cxx b/drawinglayer/source/processor2d/processorfromoutputdevice.cxx index 9875e79a7aae..ac7848829ec0 100644 --- a/drawinglayer/source/processor2d/processorfromoutputdevice.cxx +++ b/drawinglayer/source/processor2d/processorfromoutputdevice.cxx @@ -26,7 +26,6 @@ #include <drawinglayer/processor2d/processorfromoutputdevice.hxx> #include <drawinglayer/processor2d/vclmetafileprocessor2d.hxx> #include <drawinglayer/processor2d/vclpixelprocessor2d.hxx> -#include <drawinglayer/processor2d/canvasprocessor.hxx> #include <vcl/window.hxx> ////////////////////////////////////////////////////////////////////////////// @@ -53,38 +52,8 @@ namespace drawinglayer } else { -#ifdef WIN32 - // for a first AA incarnation VCL-PixelRenderer will be okay since - // simple (and fast) GDIPlus support over VCL will be used. - // Leaving the code below as a hint for what to do when we will - // use canvas renderers in the future - - //static SvtOptionsDrawinglayer aSvtOptionsDrawinglayer; - - //if(false && aSvtOptionsDrawinglayer.IsAntiAliasing()) - //{ - // // for WIN32 AA, create cairo canvas processor - // return new drawinglayer::processor2d::canvasProcessor2D(rViewInformation2D, rTargetOutDev); - //} - //else - //{ - // create Pixel Vcl-Processor - return new drawinglayer::processor2d::VclPixelProcessor2D(rViewInformation2D, rTargetOutDev); - //} -#else - static bool bTryTestCanvas(false); - - if(bTryTestCanvas) - { - // create test-cancas-Processor - return new drawinglayer::processor2d::canvasProcessor2D(rViewInformation2D, rTargetOutDev); - } - else - { - // create Pixel Vcl-Processor - return new drawinglayer::processor2d::VclPixelProcessor2D(rViewInformation2D, rTargetOutDev); - } -#endif + // create Pixel Vcl-Processor + return new drawinglayer::processor2d::VclPixelProcessor2D(rViewInformation2D, rTargetOutDev); } } } // end of namespace processor2d diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index ec5ad2d48d71..cf3c79b92638 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -615,7 +615,7 @@ namespace drawinglayer Even for XFillTransparenceItem it is used, thus it may need to be supported in UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon. Implemented for: - PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D, + PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D, PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D, PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D, PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D, @@ -1345,19 +1345,19 @@ namespace drawinglayer RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); break; } - case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D : + case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D : { - // need to handle PolyPolygonBitmapPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END - const primitive2d::PolyPolygonBitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate); + // need to handle PolyPolygonGraphicPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END + const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate); basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon()); if(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon)) { // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points // per polygon. If there are more use the splitted polygon and call recursively - const primitive2d::PolyPolygonBitmapPrimitive2D aSplitted( + const primitive2d::PolyPolygonGraphicPrimitive2D aSplitted( aLocalPolyPolygon, - rBitmapCandidate.getFillBitmap()); + rBitmapCandidate.getFillGraphic()); processBasePrimitive2D(aSplitted); } @@ -1367,46 +1367,41 @@ namespace drawinglayer if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) { - aLocalPolyPolygon.transform(maCurrentTransformation); - // calculate transformation. Get real object size, all values in FillBitmapAttribute - // are relative to the unified object - const attribute::FillBitmapAttribute& rFillBitmapAttribute = rBitmapCandidate .getFillBitmap(); - const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aLocalPolyPolygon)); - const basegfx::B2DVector aOutlineSize(aOutlineRange.getRange()); + // #121194# Changed implementation and checked usages fo convert to metafile, + // presentation start (uses SvtGraphicFill) and printing. - // get absolute values - const basegfx::B2DVector aFillBitmapSize(rFillBitmapAttribute.getSize() * aOutlineSize); - const basegfx::B2DPoint aFillBitmapTopLeft(rFillBitmapAttribute.getTopLeft() * aOutlineSize); + // calculate transformation. Get real object size, all values in FillGraphicAttribute + // are relative to the unified object + aLocalPolyPolygon.transform(maCurrentTransformation); + const basegfx::B2DVector aOutlineSize(aLocalPolyPolygon.getB2DRange().getRange()); // the scaling needs scale from pixel to logic coordinate system - const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx(); - Size aBmpSizePixel(rBitmapEx.GetSizePixel()); - - if(!aBmpSizePixel.Width()) - { - aBmpSizePixel.Width() = 1; - } - - if(!aBmpSizePixel.Height()) - { - aBmpSizePixel.Height() = 1; - } + const attribute::FillGraphicAttribute& rFillGraphicAttribute = rBitmapCandidate.getFillGraphic(); + const Size aBmpSizePixel(rFillGraphicAttribute.getGraphic().GetSizePixel()); + + // setup transformation like in impgrfll. Multiply with aOutlineSize + // to get from unit coordinates in rFillGraphicAttribute.getGraphicRange() + // to object coordinates with object's top left being at (0,0). Divide + // by pixel size so that scale from pixel to logic will work in SvtGraphicFill. + const basegfx::B2DVector aTransformScale( + rFillGraphicAttribute.getGraphicRange().getRange() / + basegfx::B2DVector( + std::max(1.0, double(aBmpSizePixel.Width())), + std::max(1.0, double(aBmpSizePixel.Height()))) * + aOutlineSize); + const basegfx::B2DPoint aTransformPosition( + rFillGraphicAttribute.getGraphicRange().getMinimum() * aOutlineSize); // setup transformation like in impgrfll SvtGraphicFill::Transform aTransform; // scale values are divided by bitmap pixel sizes - aTransform.matrix[0] = aFillBitmapSize.getX() / aBmpSizePixel.Width(); - aTransform.matrix[4] = aFillBitmapSize.getY() / aBmpSizePixel.Height(); + aTransform.matrix[0] = aTransformScale.getX(); + aTransform.matrix[4] = aTransformScale.getY(); // translates are absolute - aTransform.matrix[2] = aFillBitmapTopLeft.getX(); - aTransform.matrix[5] = aFillBitmapTopLeft.getY(); - - // setup fill graphic like in impgrfll - Graphic aFillGraphic = Graphic(rBitmapEx); - aFillGraphic.SetPrefMapMode(MapMode(MAP_PIXEL)); - aFillGraphic.SetPrefSize(aBmpSizePixel); + aTransform.matrix[2] = aTransformPosition.getX(); + aTransform.matrix[5] = aTransformPosition.getY(); pSvtGraphicFill = new SvtGraphicFill( getFillPolyPolygon(aLocalPolyPolygon), @@ -1415,14 +1410,14 @@ namespace drawinglayer SvtGraphicFill::fillEvenOdd, SvtGraphicFill::fillTexture, aTransform, - rFillBitmapAttribute.getTiling(), + rFillGraphicAttribute.getTiling(), SvtGraphicFill::hatchSingle, Color(), SvtGraphicFill::gradientLinear, Color(), Color(), 0, - aFillGraphic); + rFillGraphicAttribute.getGraphic()); } // Do use decomposition; encapsulate with SvtGraphicFill @@ -1806,7 +1801,7 @@ namespace drawinglayer } // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and - // PolyPolygonBitmapPrimitive2D are derived from PolyPolygonColorPrimitive2D. + // PolyPolygonGraphicPrimitive2D are derived from PolyPolygonColorPrimitive2D. // Check also for correct ID to exclude derived implementations if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID()) { diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index dde9bb5724dc..1f2d518e3c9d 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -24,7 +24,7 @@ #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> -#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx> #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> #include <drawinglayer/primitive2d/maskprimitive2d.hxx> #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> @@ -179,10 +179,10 @@ namespace drawinglayer RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); break; } - case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D : + case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D : { // direct draw of fillBitmapPrimitive - RenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D& >(rCandidate)); + RenderFillGraphicPrimitive2D(static_cast< const primitive2d::FillGraphicPrimitive2D& >(rCandidate)); break; } case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D : @@ -191,10 +191,10 @@ namespace drawinglayer RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate)); break; } - case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D : + case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D : { // direct draw of bitmap - RenderPolyPolygonBitmapPrimitive2D(static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate)); + RenderPolyPolygonGraphicPrimitive2D(static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate)); break; } case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx index cced61242c17..d129251dbfc1 100644 --- a/drawinglayer/source/processor2d/vclprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx @@ -28,8 +28,8 @@ #include <vclhelperbitmaptransform.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> #include <vclhelperbitmaprender.hxx> -#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx> -#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx> +#include <drawinglayer/attribute/sdrfillgraphicattribute.hxx> +#include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx> #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> #include <vclhelpergradient.hxx> #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> @@ -52,6 +52,7 @@ #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx> #include <basegfx/color/bcolor.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <vcl/graph.hxx> #include "getdigitlanguage.hxx" @@ -474,122 +475,192 @@ namespace drawinglayer } } - void VclProcessor2D::RenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapCandidate) + void VclProcessor2D::RenderFillGraphicPrimitive2D(const primitive2d::FillGraphicPrimitive2D& rFillBitmapCandidate) { - const attribute::FillBitmapAttribute& rFillBitmapAttribute(rFillBitmapCandidate.getFillBitmap()); + const attribute::FillGraphicAttribute& rFillGraphicAttribute(rFillBitmapCandidate.getFillGraphic()); bool bPrimitiveAccepted(false); + static bool bTryTilingDirect = true; - if(rFillBitmapAttribute.getTiling()) - { - // decompose matrix to check for shear, rotate and mirroring - basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rFillBitmapCandidate.getTransformation()); - basegfx::B2DVector aScale, aTranslate; - double fRotate, fShearX; - aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); + // #121194# when tiling is used and content is bitmap-based, do direct tiling in the + // renderer on pixel base to ensure tight fitting. Do not do this when + // the fill is rotated or sheared. - if(basegfx::fTools::equalZero(fRotate) && basegfx::fTools::equalZero(fShearX)) + // ovveride static bool (for debug) and tiling is active + if(bTryTilingDirect && rFillGraphicAttribute.getTiling()) + { + // content is bitmap(ex) + // + // for SVG support, force decomposition when SVG is present. This will lead to use + // the primitive representation of the svg directly. + // + // when graphic is animated, force decomposition to use the correct graphic, else + // fill style will not be animated + if(GRAPHIC_BITMAP == rFillGraphicAttribute.getGraphic().GetType() + && !rFillGraphicAttribute.getGraphic().getSvgData().get() + && !rFillGraphicAttribute.getGraphic().IsAnimated()) { - // no shear or rotate, draw direct in pixel coordinates - bPrimitiveAccepted = true; - BitmapEx aBitmapEx(rFillBitmapAttribute.getBitmapEx()); - bool bPainted(false); - - if(maBColorModifierStack.count()) + // decompose matrix to check for shear, rotate and mirroring + basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rFillBitmapCandidate.getTransformation()); + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + // when nopt rotated/sheared + if(basegfx::fTools::equalZero(fRotate) && basegfx::fTools::equalZero(fShearX)) { - aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx); - - if(aBitmapEx.IsEmpty()) - { - // color gets completely replaced, get it - const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); - basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); - aPolygon.transform(aLocalTransform); + // no shear or rotate, draw direct in pixel coordinates + bPrimitiveAccepted = true; - mpOutputDevice->SetFillColor(Color(aModifiedColor)); - mpOutputDevice->SetLineColor(); - mpOutputDevice->DrawPolygon(aPolygon); + // transform object range to device coordinates (pixels). Use + // the device transformation for better accuracy + basegfx::B2DRange aObjectRange(aTranslate, aTranslate + aScale); + aObjectRange.transform(mpOutputDevice->GetViewTransformation()); - bPainted = true; - } - } - - if(!bPainted) - { - const basegfx::B2DPoint aObjTopLeft(aTranslate.getX(), aTranslate.getY()); - const basegfx::B2DPoint aObjBottomRight(aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY()); - const Point aObjTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjTopLeft.getX(), (sal_Int32)aObjTopLeft.getY()))); - const Point aObjBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjBottomRight.getX(), (sal_Int32)aObjBottomRight.getY()))); - - const basegfx::B2DPoint aBmpTopLeft(aLocalTransform * rFillBitmapAttribute.getTopLeft()); - const basegfx::B2DPoint aBmpBottomRight(aLocalTransform * basegfx::B2DPoint(rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize())); - const Point aBmpTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpTopLeft.getX(), (sal_Int32)aBmpTopLeft.getY()))); - const Point aBmpBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpBottomRight.getX(), (sal_Int32)aBmpBottomRight.getY()))); - - sal_Int32 nOWidth(aObjBR.X() - aObjTL.X()); - sal_Int32 nOHeight(aObjBR.Y() - aObjTL.Y()); + // extract discrete size of object + const sal_Int32 nOWidth(basegfx::fround(aObjectRange.getWidth())); + const sal_Int32 nOHeight(basegfx::fround(aObjectRange.getHeight())); // only do something when object has a size in discrete units if(nOWidth > 0 && nOHeight > 0) { - sal_Int32 nBWidth(aBmpBR.X() - aBmpTL.X()); - sal_Int32 nBHeight(aBmpBR.Y() - aBmpTL.Y()); + // transform graphic range to device coordinates (pixels). Use + // the device transformation for better accuracy + basegfx::B2DRange aGraphicRange(rFillGraphicAttribute.getGraphicRange()); + aGraphicRange.transform(mpOutputDevice->GetViewTransformation() * aLocalTransform); + + // extract discrete size of graphic + const sal_Int32 nBWidth(basegfx::fround(aGraphicRange.getWidth())); + const sal_Int32 nBHeight(basegfx::fround(aGraphicRange.getHeight())); // only do something when bitmap fill has a size in discrete units if(nBWidth > 0 && nBHeight > 0) { - sal_Int32 nBLeft(aBmpTL.X()); - sal_Int32 nBTop(aBmpTL.Y()); - - if(nBLeft > aObjTL.X()) + // nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it + // in vcl many times, create a size-optimized version + const Size aNeededBitmapSizePixel(nBWidth, nBHeight); + BitmapEx aBitmapEx(rFillGraphicAttribute.getGraphic().GetBitmapEx( + GraphicConversionParameters( + aNeededBitmapSizePixel, // get the correct size immediately + false, // no unlimited size + false, // Use AntiAliasing + false, //SnapHorVerLines + true // ScaleHighQuality + ))); + bool bPainted(false); + + if(maBColorModifierStack.count()) { - nBLeft -= ((nBLeft / nBWidth) + 1L) * nBWidth; - } + // when color modifier, apply to bitmap + aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx); - if(nBLeft + nBWidth <= aObjTL.X()) - { - nBLeft -= (nBLeft / nBWidth) * nBWidth; - } + // impModifyBitmapEx uses empty bitmap as sign to return that + // the content will be completely replaced to mono color, use shortcut + if(aBitmapEx.IsEmpty()) + { + // color gets completely replaced, get it + const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor())); + basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon()); + aPolygon.transform(aLocalTransform); - if(nBTop > aObjTL.Y()) - { - nBTop -= ((nBTop / nBHeight) + 1L) * nBHeight; + mpOutputDevice->SetFillColor(Color(aModifiedColor)); + mpOutputDevice->SetLineColor(); + mpOutputDevice->DrawPolygon(aPolygon); + + bPainted = true; + } } - if(nBTop + nBHeight <= aObjTL.Y()) + if(!bPainted) { - nBTop -= (nBTop / nBHeight) * nBHeight; - } + sal_Int32 nBLeft(basegfx::fround(aGraphicRange.getMinX())); + sal_Int32 nBTop(basegfx::fround(aGraphicRange.getMinY())); + const sal_Int32 nOLeft(basegfx::fround(aObjectRange.getMinX())); + const sal_Int32 nOTop(basegfx::fround(aObjectRange.getMinY())); + sal_Int32 nPosX(0); + sal_Int32 nPosY(0); + + if(nBLeft > nOLeft) + { + const sal_Int32 nDiff((nBLeft / nBWidth) + 1); - // nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it - // in vcl many times, create a size-optimized version - const Size aNeededBitmapSizePixel(nBWidth, nBHeight); + nPosX -= nDiff; + nBLeft -= nDiff * nBWidth; + } - if(aNeededBitmapSizePixel != aBitmapEx.GetSizePixel()) - { - aBitmapEx.Scale(aNeededBitmapSizePixel); - } + if(nBLeft + nBWidth <= nOLeft) + { + const sal_Int32 nDiff(-nBLeft / nBWidth); - // prepare OutDev - const Point aEmptyPoint(0, 0); - const Rectangle aVisiblePixel(aEmptyPoint, mpOutputDevice->GetOutputSizePixel()); - const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled()); - mpOutputDevice->EnableMapMode(false); + nPosX += nDiff; + nBLeft += nDiff * nBWidth; + } - for(sal_Int32 nXPos(nBLeft); nXPos < aObjTL.X() + nOWidth; nXPos += nBWidth) - { - for(sal_Int32 nYPos(nBTop); nYPos < aObjTL.Y() + nOHeight; nYPos += nBHeight) + if(nBTop > nOTop) + { + const sal_Int32 nDiff((nBTop / nBHeight) + 1); + + nPosY -= nDiff; + nBTop -= nDiff * nBHeight; + } + + if(nBTop + nBHeight <= nOTop) + { + const sal_Int32 nDiff(-nBTop / nBHeight); + + nPosY += nDiff; + nBTop += nDiff * nBHeight; + } + + // prepare OutDev + const Point aEmptyPoint(0, 0); + const Rectangle aVisiblePixel(aEmptyPoint, mpOutputDevice->GetOutputSizePixel()); + const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled()); + mpOutputDevice->EnableMapMode(false); + + // check if offset is used + const sal_Int32 nOffsetX(basegfx::fround(rFillGraphicAttribute.getOffsetX() * nBWidth)); + + if(nOffsetX) + { + // offset in X, so iterate over Y first and draw lines + for(sal_Int32 nYPos(nBTop); nYPos < nOTop + nOHeight; nYPos += nBHeight, nPosY++) + { + for(sal_Int32 nXPos(nPosY % 2 ? nBLeft - nBWidth + nOffsetX : nBLeft); + nXPos < nOLeft + nOWidth; nXPos += nBWidth) + { + const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel); + + if(aOutRectPixel.IsOver(aVisiblePixel)) + { + mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx); + } + } + } + } + else { - const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel); + // check if offset is used + const sal_Int32 nOffsetY(basegfx::fround(rFillGraphicAttribute.getOffsetY() * nBHeight)); - if(aOutRectPixel.IsOver(aVisiblePixel)) + // possible offset in Y, so iterate over X first and draw columns + for(sal_Int32 nXPos(nBLeft); nXPos < nOLeft + nOWidth; nXPos += nBWidth, nPosX++) { - mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx); + for(sal_Int32 nYPos(nPosX % 2 ? nBTop - nBHeight + nOffsetY : nBTop); + nYPos < nOTop + nOHeight; nYPos += nBHeight) + { + const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel); + + if(aOutRectPixel.IsOver(aVisiblePixel)) + { + mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx); + } + } } } - } - // restore OutDev - mpOutputDevice->EnableMapMode(bWasEnabled); + // restore OutDev + mpOutputDevice->EnableMapMode(bWasEnabled); + } } } } @@ -641,90 +712,105 @@ namespace drawinglayer } } - // direct draw of bitmap - void VclProcessor2D::RenderPolyPolygonBitmapPrimitive2D(const primitive2d::PolyPolygonBitmapPrimitive2D& rPolygonCandidate) + // direct draw of Graphic + void VclProcessor2D::RenderPolyPolygonGraphicPrimitive2D(const primitive2d::PolyPolygonGraphicPrimitive2D& rPolygonCandidate) { bool bDone(false); const basegfx::B2DPolyPolygon& rPolyPolygon = rPolygonCandidate.getB2DPolyPolygon(); - if(rPolyPolygon.count()) + // #121194# Todo: check if this works + if(!rPolyPolygon.count()) { - const attribute::FillBitmapAttribute& rFillBitmapAttribute = rPolygonCandidate.getFillBitmap(); - const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx(); + // empty polyPolygon, done + bDone = true; + } + else + { + const attribute::FillGraphicAttribute& rFillGraphicAttribute = rPolygonCandidate.getFillGraphic(); - if(rBitmapEx.IsEmpty()) - { - // empty bitmap, done - bDone = true; - } - else + // try to catch cases where the graphic will be color-modified to a single + // color (e.g. shadow) + switch(rFillGraphicAttribute.getGraphic().GetType()) { - // try to catch cases where the bitmap will be color-modified to a single - // color (e.g. shadow). This would NOT be optimizable with an transparence channel - // at the Bitmap which we do not have here. When this should change, this - // optimization has to be reworked accordingly. - const sal_uInt32 nBColorModifierStackCount(maBColorModifierStack.count()); - - if(nBColorModifierStackCount) + case GRAPHIC_GDIMETAFILE: { - const basegfx::BColorModifier& rTopmostModifier = maBColorModifierStack.getBColorModifier(nBColorModifierStackCount - 1); - - if(basegfx::BCOLORMODIFYMODE_REPLACE == rTopmostModifier.getMode()) + // metafiles are potentially transparent, cannot optimize, not done + break; + } + case GRAPHIC_BITMAP: + { + if(!rFillGraphicAttribute.getGraphic().IsTransparent() && !rFillGraphicAttribute.getGraphic().IsAlpha()) { - // the bitmap fill is in unified color, so we can replace it with - // a single polygon fill. The form of the fill depends on tiling - if(rFillBitmapAttribute.getTiling()) - { - // with tiling, fill the whole PolyPolygon with the modifier color - basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon); + // bitmap is not transparent and has no alpha + const sal_uInt32 nBColorModifierStackCount(maBColorModifierStack.count()); - aLocalPolyPolygon.transform(maCurrentTransformation); - mpOutputDevice->SetLineColor(); - mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); - mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); - } - else + if(nBColorModifierStackCount) { - // without tiling, only the area common to the bitmap tile and the - // PolyPolygon is filled. Create the bitmap tile area in object - // coordinates. For this, the object transformation needs to be created - // from the already scaled PolyPolygon. The tile area in object - // coordinates wil always be non-rotated, so it's not necessary to - // work with a polygon here - basegfx::B2DRange aTileRange(rFillBitmapAttribute.getTopLeft(), - rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize()); - const basegfx::B2DRange aPolyPolygonRange(rPolyPolygon.getB2DRange()); - basegfx::B2DHomMatrix aNewObjectTransform; - - aNewObjectTransform.set(0, 0, aPolyPolygonRange.getWidth()); - aNewObjectTransform.set(1, 1, aPolyPolygonRange.getHeight()); - aNewObjectTransform.set(0, 2, aPolyPolygonRange.getMinX()); - aNewObjectTransform.set(1, 2, aPolyPolygonRange.getMinY()); - aTileRange.transform(aNewObjectTransform); - - // now clip the object polyPolygon against the tile range - // to get the common area (OR) - basegfx::B2DPolyPolygon aTarget = basegfx::tools::clipPolyPolygonOnRange(rPolyPolygon, aTileRange, true, false); - - if(aTarget.count()) + const basegfx::BColorModifier& rTopmostModifier = maBColorModifierStack.getBColorModifier(nBColorModifierStackCount - 1); + + if(basegfx::BCOLORMODIFYMODE_REPLACE == rTopmostModifier.getMode()) { - aTarget.transform(maCurrentTransformation); - mpOutputDevice->SetLineColor(); - mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); - mpOutputDevice->DrawPolyPolygon(aTarget); + // the bitmap fill is in unified color, so we can replace it with + // a single polygon fill. The form of the fill depends on tiling + if(rFillGraphicAttribute.getTiling()) + { + // with tiling, fill the whole PolyPolygon with the modifier color + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon); + + aLocalPolyPolygon.transform(maCurrentTransformation); + mpOutputDevice->SetLineColor(); + mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); + mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); + } + else + { + // without tiling, only the area common to the bitmap tile and the + // PolyPolygon is filled. Create the bitmap tile area in object + // coordinates. For this, the object transformation needs to be created + // from the already scaled PolyPolygon. The tile area in object + // coordinates wil always be non-rotated, so it's not necessary to + // work with a polygon here + basegfx::B2DRange aTileRange(rFillGraphicAttribute.getGraphicRange()); + const basegfx::B2DRange aPolyPolygonRange(rPolyPolygon.getB2DRange()); + const basegfx::B2DHomMatrix aNewObjectTransform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + aPolyPolygonRange.getRange(), + aPolyPolygonRange.getMinimum())); + + aTileRange.transform(aNewObjectTransform); + + // now clip the object polyPolygon against the tile range + // to get the common area + basegfx::B2DPolyPolygon aTarget = basegfx::tools::clipPolyPolygonOnRange( + rPolyPolygon, + aTileRange, + true, + false); + + if(aTarget.count()) + { + aTarget.transform(maCurrentTransformation); + mpOutputDevice->SetLineColor(); + mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor())); + mpOutputDevice->DrawPolyPolygon(aTarget); + } + } + + // simplified output executed, we are done + bDone = true; } } - - bDone = true; } + break; + } + default: //GRAPHIC_NONE, GRAPHIC_DEFAULT + { + // empty graphic, we are done + bDone = true; + break; } } } - else - { - // empty polyPolygon, done - bDone = true; - } if(!bDone) { |