diff options
author | Caolán McNamara <caolanm@redhat.com> | 2018-07-31 14:20:52 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2018-07-31 18:18:36 +0200 |
commit | 2a4b054b3685aaeca5bdcb2969bcfc25365421d9 (patch) | |
tree | 19dd2dfea163744e10395065898860236638f839 | |
parent | 4f13f8ddeebca1de9fd30f0aae71e3f84383656a (diff) |
crashtesting: stack exhaustion exporting moz943243-4.svg to odg
happens on the crashtesting box, but not locally, comparing the stack frames its clear
that the stack used on the crashtester for VclMetafileProcessor2D::processBasePrimitive2D is
over double that used locally...
comparison on
> objdump -S workdir/CxxObject/drawinglayer/source/processor2d/vclmetafileprocessor2d.o |less
gives...
void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
gcc-4.8.2-3.2.mga4 has... sub $0x11e8,%rsp
vs...
gcc-8.1.1-5.fc28.x86_64 has... sub $0x4c0,%rsp
lets split up this method
Change-Id: I73ef1eb0280224988176986918a2d025344197d0
Reviewed-on: https://gerrit.libreoffice.org/58362
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r-- | drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx | 2434 | ||||
-rw-r--r-- | drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx | 42 |
2 files changed, 1288 insertions, 1188 deletions
diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index bcd18d2d1f26..a7228338c689 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -761,1368 +761,1426 @@ namespace drawinglayer } case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D : { - const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate); - bool bUsingPDFExtOutDevData(false); - basegfx::B2DVector aTranslate, aScale; - static bool bSuppressPDFExtOutDevDataSupport(false); + processGraphicPrimitive2D(static_cast<const primitive2d::GraphicPrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D : + { + processControlPrimitive2D(static_cast<const primitive2d::ControlPrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D : + { + processTextHierarchyFieldPrimitive2D(static_cast<const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D : + { + processTextHierarchyLinePrimitive2D(static_cast<const primitive2d::TextHierarchyLinePrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D : + { + processTextHierarchyBulletPrimitive2D(static_cast<const primitive2d::TextHierarchyBulletPrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D : + { + processTextHierarchyParagraphPrimitive2D(static_cast<const primitive2d::TextHierarchyParagraphPrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D : + { + processTextHierarchyBlockPrimitive2D(static_cast<const primitive2d::TextHierarchyBlockPrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : + case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D : + { + // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate + processTextSimplePortionPrimitive2D(static_cast<const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : + { + processPolygonHairlinePrimitive2D(static_cast<const primitive2d::PolygonHairlinePrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D : + { + processPolygonStrokePrimitive2D(static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D : + { + processPolygonStrokeArrowPrimitive2D(static_cast<const primitive2d::PolygonStrokeArrowPrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : + { + // direct draw of transformed BitmapEx primitive; use default processing, but without + // former testing if graphic content is inside discrete local viewport; this is not + // setup for metafile targets (metafile renderer tries to render in logic coordinates, + // the mapping is kept to the OutputDevice for better Metafile recording) + RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D : + { + processPolyPolygonGraphicPrimitive2D(static_cast<const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D : + { + processPolyPolygonHatchPrimitive2D(static_cast<const primitive2d::PolyPolygonHatchPrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D : + { + processPolyPolygonGradientPrimitive2D(static_cast<const primitive2d::PolyPolygonGradientPrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : + { + processPolyPolygonColorPrimitive2D(static_cast<const primitive2d::PolyPolygonColorPrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_MASKPRIMITIVE2D : + { + processMaskPrimitive2D(static_cast<const primitive2d::MaskPrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D : + { + // modified color group. Force output to unified color. Use default pocessing. + RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D : + { + processUnifiedTransparencePrimitive2D(static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D : + { + processTransparencePrimitive2D(static_cast<const primitive2d::TransparencePrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : + { + // use default transform group pocessing + RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : + { + // new XDrawPage for ViewInformation2D + RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : + { + // use default marker array pocessing + RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : + { + // use default point array pocessing + RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate)); + break; + } + case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D : + { + processStructureTagPrimitive2D(static_cast<const primitive2d::StructureTagPrimitive2D&>(rCandidate)); + break; + } + case PRIMITIVE2D_ID_EPSPRIMITIVE2D : + { + RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate)); + break; + } + default : + { + // process recursively + process(rCandidate); + break; + } + } + } - if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport) + void VclMetafileProcessor2D::processGraphicPrimitive2D(const primitive2d::GraphicPrimitive2D& rGraphicPrimitive) + { + bool bUsingPDFExtOutDevData(false); + basegfx::B2DVector aTranslate, aScale; + static bool bSuppressPDFExtOutDevDataSupport(false); + + if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport) + { + // emulate data handling from UnoControlPDFExportContact, original see + // svtools/source/graphic/grfmgr.cxx + const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic(); + + if(rGraphic.IsGfxLink()) + { + const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr(); + + if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted()) { - // emulate data handling from UnoControlPDFExportContact, original see - // svtools/source/graphic/grfmgr.cxx - const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic(); + const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform(); + double fRotate, fShearX; + rTransform.decompose(aScale, aTranslate, fRotate, fShearX); - if(rGraphic.IsGfxLink()) + if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) ) { - const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr(); - - if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted()) - { - const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform(); - double fRotate, fShearX; - rTransform.decompose(aScale, aTranslate, fRotate, fShearX); - - if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) ) - { - bUsingPDFExtOutDevData = true; - mpPDFExtOutDevData->BeginGroup(); - } - } + bUsingPDFExtOutDevData = true; + mpPDFExtOutDevData->BeginGroup(); } } + } + } + + // process recursively and add MetaFile comment + process(rGraphicPrimitive); - // process recursively and add MetaFile comment - process(rGraphicPrimitive); + if(bUsingPDFExtOutDevData) + { + // emulate data handling from UnoControlPDFExportContact, original see + // svtools/source/graphic/grfmgr.cxx + const basegfx::B2DRange aCurrentRange( + aTranslate.getX(), aTranslate.getY(), + aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY()); + const ::tools::Rectangle aCurrentRect( + sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())), + sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY()))); + const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr(); + // fdo#72530 don't pass empty Rectangle to EndGroup + ::tools::Rectangle aCropRect(aCurrentRect); + + if(rAttr.IsCropped()) + { + // calculate scalings between real image size and logic object size. This + // is necessary since the crop values are relative to original bitmap size + double fFactorX(1.0); + double fFactorY(1.0); - if(bUsingPDFExtOutDevData) { - // emulate data handling from UnoControlPDFExportContact, original see - // svtools/source/graphic/grfmgr.cxx - const basegfx::B2DRange aCurrentRange( - aTranslate.getX(), aTranslate.getY(), - aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY()); - const ::tools::Rectangle aCurrentRect( - sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())), - sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY()))); - const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr(); - // fdo#72530 don't pass empty Rectangle to EndGroup - ::tools::Rectangle aCropRect(aCurrentRect); - - if(rAttr.IsCropped()) + const MapMode aMapMode100thmm(MapUnit::Map100thMM); + const Size aBitmapSize(OutputDevice::LogicToLogic( + rGraphicPrimitive.getGraphicObject().GetPrefSize(), + rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm)); + const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop()); + const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop()); + + if(!basegfx::fTools::equalZero(fDivX)) { - // calculate scalings between real image size and logic object size. This - // is necessary since the crop values are relative to original bitmap size - double fFactorX(1.0); - double fFactorY(1.0); - - { - const MapMode aMapMode100thmm(MapUnit::Map100thMM); - const Size aBitmapSize(OutputDevice::LogicToLogic( - rGraphicPrimitive.getGraphicObject().GetPrefSize(), - rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm)); - const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop()); - const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop()); - - if(!basegfx::fTools::equalZero(fDivX)) - { - fFactorX = aScale.getX() / fDivX; - } - - if(!basegfx::fTools::equalZero(fDivY)) - { - fFactorY = aScale.getY() / fDivY; - } - } - - // calculate crop range and rect - basegfx::B2DRange aCropRange; - aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY)); - aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY)); - - aCropRect = ::tools::Rectangle( - sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())), - sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY()))); + fFactorX = aScale.getX() / fDivX; } - // #i123295# 3rd param is uncropped rect, 4th is cropped. The primitive has the cropped - // object transformation, thus aCurrentRect *is* the clip region while aCropRect is the expanded, - // uncropped region. Thus, correct order is aCropRect, aCurrentRect - mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(), - rAttr.GetTransparency(), - aCropRect, - aCurrentRect); + if(!basegfx::fTools::equalZero(fDivY)) + { + fFactorY = aScale.getY() / fDivY; + } } - break; + // calculate crop range and rect + basegfx::B2DRange aCropRange; + aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY)); + aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY)); + + aCropRect = ::tools::Rectangle( + sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())), + sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY()))); } - case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D : + + // #i123295# 3rd param is uncropped rect, 4th is cropped. The primitive has the cropped + // object transformation, thus aCurrentRect *is* the clip region while aCropRect is the expanded, + // uncropped region. Thus, correct order is aCropRect, aCurrentRect + mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(), + rAttr.GetTransparency(), + aCropRect, + aCurrentRect); + } + } + + void VclMetafileProcessor2D::processControlPrimitive2D(const primitive2d::ControlPrimitive2D& rControlPrimitive) + { + const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl()); + bool bIsPrintableControl(false); + + // find out if control is printable + if(rXControl.is()) + { + try { - const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate); - const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl()); - bool bIsPrintableControl(false); + uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY); + uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is() + ? xModelProperties->getPropertySetInfo() + : uno::Reference< beans::XPropertySetInfo >()); + const OUString sPrintablePropertyName("Printable"); - // find out if control is printable - if(rXControl.is()) + if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName)) { - try - { - uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY); - uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is() - ? xModelProperties->getPropertySetInfo() - : uno::Reference< beans::XPropertySetInfo >()); - const OUString sPrintablePropertyName("Printable"); - - if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName)) - { - OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl); - } - } - catch(const uno::Exception&) - { - OSL_FAIL("VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!"); - } + OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl); } + } + catch(const uno::Exception&) + { + OSL_FAIL("VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!"); + } + } - // PDF export and printing only for printable controls - if(bIsPrintableControl) + // PDF export and printing only for printable controls + if(bIsPrintableControl) + { + const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields()); + bool bDoProcessRecursively(true); + + if(bPDFExport) + { + // PDF export. Emulate data handling from UnoControlPDFExportContact + // I have now moved describePDFControl to toolkit, thus i can implement the PDF + // form control support now as follows + std::unique_ptr< vcl::PDFWriter::AnyWidget > pPDFControl( + ::toolkitform::describePDFControl( rXControl, *mpPDFExtOutDevData ) ); + + if(pPDFControl.get()) { - const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields()); - bool bDoProcessRecursively(true); + // still need to fill in the location (is a class Rectangle) + const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D())); + const ::tools::Rectangle aRectLogic( + static_cast<sal_Int32>(floor(aRangeLogic.getMinX())), static_cast<sal_Int32>(floor(aRangeLogic.getMinY())), + static_cast<sal_Int32>(ceil(aRangeLogic.getMaxX())), static_cast<sal_Int32>(ceil(aRangeLogic.getMaxY()))); + pPDFControl->Location = aRectLogic; - if(bPDFExport) - { - // PDF export. Emulate data handling from UnoControlPDFExportContact - // I have now moved describePDFControl to toolkit, thus i can implement the PDF - // form control support now as follows - std::unique_ptr< vcl::PDFWriter::AnyWidget > pPDFControl( - ::toolkitform::describePDFControl( rXControl, *mpPDFExtOutDevData ) ); - - if(pPDFControl.get()) - { - // still need to fill in the location (is a class Rectangle) - const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D())); - const ::tools::Rectangle aRectLogic( - static_cast<sal_Int32>(floor(aRangeLogic.getMinX())), static_cast<sal_Int32>(floor(aRangeLogic.getMinY())), - static_cast<sal_Int32>(ceil(aRangeLogic.getMaxX())), static_cast<sal_Int32>(ceil(aRangeLogic.getMaxY()))); - pPDFControl->Location = aRectLogic; - - Size aFontSize(pPDFControl->TextFont.GetFontSize()); - aFontSize = OutputDevice::LogicToLogic(aFontSize, MapMode(MapUnit::MapPoint), mpOutputDevice->GetMapMode()); - pPDFControl->TextFont.SetFontSize(aFontSize); - - mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form); - mpPDFExtOutDevData->CreateControl(*pPDFControl.get()); - mpPDFExtOutDevData->EndStructureElement(); - - // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject); - // do not process recursively - bDoProcessRecursively = false; - } - else - { - // PDF export did not work, try simple output. - // Fallback to printer output by not setting bDoProcessRecursively - // to false. - } - } + Size aFontSize(pPDFControl->TextFont.GetFontSize()); + aFontSize = OutputDevice::LogicToLogic(aFontSize, MapMode(MapUnit::MapPoint), mpOutputDevice->GetMapMode()); + pPDFControl->TextFont.SetFontSize(aFontSize); - // #i93169# used flag the wrong way; true means that nothing was done yet - if(bDoProcessRecursively) - { - // printer output - try - { - // remember old graphics and create new - uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW); - const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics()); - const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics()); - - if(xNewGraphics.is()) - { - // link graphics and view - xControlView->setGraphics(xNewGraphics); - - // get position - const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform()); - const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0)); - - // draw it - xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY())); - bDoProcessRecursively = false; - - // restore original graphics - xControlView->setGraphics(xOriginalGraphics); - } - } - catch( const uno::Exception& ) - { - OSL_FAIL("VclMetafileProcessor2D: Printing of Control failed, caught an exception!"); - } - } + mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form); + mpPDFExtOutDevData->CreateControl(*pPDFControl.get()); + mpPDFExtOutDevData->EndStructureElement(); - // process recursively if not done yet to export as decomposition (bitmap) - if(bDoProcessRecursively) - { - process(rControlPrimitive); - } + // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject); + // do not process recursively + bDoProcessRecursively = false; + } + else + { + // PDF export did not work, try simple output. + // Fallback to printer output by not setting bDoProcessRecursively + // to false. } - - break; } - case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D : - { - // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to) - // thus do the MetafileAction embedding stuff but just handle recursively. - const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate); - const OString aCommentStringCommon("FIELD_SEQ_BEGIN"); - const OString aCommentStringPage("FIELD_SEQ_BEGIN;PageField"); - const OString aCommentStringEnd("FIELD_SEQ_END"); - OUString aURL; - switch(rFieldPrimitive.getType()) + // #i93169# used flag the wrong way; true means that nothing was done yet + if(bDoProcessRecursively) + { + // printer output + try { - default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON : - { - mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon)); - break; - } - case drawinglayer::primitive2d::FIELD_TYPE_PAGE : - { - mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage)); - break; - } - case drawinglayer::primitive2d::FIELD_TYPE_URL : + // remember old graphics and create new + uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW); + const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics()); + const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics()); + + if(xNewGraphics.is()) { - aURL = rFieldPrimitive.getValue("URL"); + // link graphics and view + xControlView->setGraphics(xNewGraphics); - if (!aURL.isEmpty()) - { - mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast<const sal_uInt8*>(aURL.getStr()), 2 * aURL.getLength())); - } + // get position + const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform()); + const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0)); - break; + // draw it + xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY())); + bDoProcessRecursively = false; + + // restore original graphics + xControlView->setGraphics(xOriginalGraphics); } } - - // process recursively - primitive2d::Primitive2DContainer rContent; - rFieldPrimitive.get2DDecomposition(rContent, getViewInformation2D()); - process(rContent); - - // for the end comment the type is not relevant yet, they are all the same. Just add. - mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd)); - - if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType()) + catch( const uno::Exception& ) { - // emulate data handling from ImpEditEngine::Paint - const basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D())); - const ::tools::Rectangle aRectLogic( - static_cast<sal_Int32>(floor(aViewRange.getMinX())), static_cast<sal_Int32>(floor(aViewRange.getMinY())), - static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), static_cast<sal_Int32>(ceil(aViewRange.getMaxY()))); - vcl::PDFExtOutDevBookmarkEntry aBookmark; - aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic); - aBookmark.aBookmark = aURL; - std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks(); - rBookmarks.push_back( aBookmark ); + OSL_FAIL("VclMetafileProcessor2D: Printing of Control failed, caught an exception!"); } - - break; } - case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D : - { - const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate); - const OString aCommentString("XTEXT_EOL"); - // process recursively and add MetaFile comment - process(rLinePrimitive); - mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); + // process recursively if not done yet to export as decomposition (bitmap) + if(bDoProcessRecursively) + { + process(rControlPrimitive); + } + } + } + void VclMetafileProcessor2D::processTextHierarchyFieldPrimitive2D(const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive) + { + // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to) + // thus do the MetafileAction embedding stuff but just handle recursively. + const OString aCommentStringCommon("FIELD_SEQ_BEGIN"); + const OString aCommentStringPage("FIELD_SEQ_BEGIN;PageField"); + const OString aCommentStringEnd("FIELD_SEQ_END"); + OUString aURL; + + switch(rFieldPrimitive.getType()) + { + default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON : + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon)); break; } - case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D : + case drawinglayer::primitive2d::FIELD_TYPE_PAGE : { - // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The - // "XTEXT_EOC" is used, use here, too. - const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate); - const OString aCommentString("XTEXT_EOC"); - - // process recursively and add MetaFile comment - process(rBulletPrimitive); - mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); - + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage)); break; } - case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D : + case drawinglayer::primitive2d::FIELD_TYPE_URL : { - const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate); - const OString aCommentString("XTEXT_EOP"); - - if(mpPDFExtOutDevData) - { - // emulate data handling from ImpEditEngine::Paint - mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph ); - } + aURL = rFieldPrimitive.getValue("URL"); - // process recursively and add MetaFile comment - process(rParagraphPrimitive); - mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); - - if(mpPDFExtOutDevData) + if (!aURL.isEmpty()) { - // emulate data handling from ImpEditEngine::Paint - mpPDFExtOutDevData->EndStructureElement(); + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast<const sal_uInt8*>(aURL.getStr()), 2 * aURL.getLength())); } break; } - case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D : - { - const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate); - const OString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN"); - const OString aCommentStringB("XTEXT_PAINTSHAPE_END"); + } - // add MetaFile comment, process recursively and add MetaFile comment - mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA)); - process(rBlockPrimitive); - mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB)); + // process recursively + primitive2d::Primitive2DContainer rContent; + rFieldPrimitive.get2DDecomposition(rContent, getViewInformation2D()); + process(rContent); - break; - } - case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D : - case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D : - { - // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate - const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate); - // const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate); + // for the end comment the type is not relevant yet, they are all the same. Just add. + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd)); - // Adapt evtl. used special DrawMode - const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode()); - adaptTextToFillDrawMode(); + if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType()) + { + // emulate data handling from ImpEditEngine::Paint + const basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D())); + const ::tools::Rectangle aRectLogic( + static_cast<sal_Int32>(floor(aViewRange.getMinX())), static_cast<sal_Int32>(floor(aViewRange.getMinY())), + static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), static_cast<sal_Int32>(ceil(aViewRange.getMaxY()))); + vcl::PDFExtOutDevBookmarkEntry aBookmark; + aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic); + aBookmark.aBookmark = aURL; + std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks(); + rBookmarks.push_back( aBookmark ); + } + } - // directdraw of text simple portion; use default processing - RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate); + void VclMetafileProcessor2D::processTextHierarchyLinePrimitive2D(const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive) + { + const OString aCommentString("XTEXT_EOL"); - // restore DrawMode - mpOutputDevice->SetDrawMode(nOriginalDrawMode); + // process recursively and add MetaFile comment + process(rLinePrimitive); + mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); + } - // #i101169# if(pTextDecoratedCandidate) - { - // support for TEXT_ MetaFile actions only for decorated texts - if(!mxBreakIterator.is()) - { - uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); - mxBreakIterator = i18n::BreakIterator::create(xContext); - } + void VclMetafileProcessor2D::processTextHierarchyBulletPrimitive2D(const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive) + { + // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The + // "XTEXT_EOC" is used, use here, too. + const OString aCommentString("XTEXT_EOC"); - const OUString& rTxt = rTextCandidate.getText(); - const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength()); + // process recursively and add MetaFile comment + process(rBulletPrimitive); + mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); + } - if(nTextLength) - { - const css::lang::Locale& rLocale = rTextCandidate.getLocale(); - const sal_Int32 nTextPosition(rTextCandidate.getTextPosition()); - - sal_Int32 nDone; - sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone)); - css::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, css::i18n::WordType::ANY_WORD, true)); - sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale)); - const OString aCommentStringA("XTEXT_EOC"); - const OString aCommentStringB("XTEXT_EOW"); - const OString aCommentStringC("XTEXT_EOS"); - - for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++) - { - // create the entries for the respective break positions - if(i == nNextCellBreak) - { - mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition)); - nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); - } - if(i == nNextWordBoundary.endPos) - { - mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition)); - nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, css::i18n::WordType::ANY_WORD, true); - } - if(i == nNextSentenceBreak) - { - mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition)); - nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale); - } - } - } - } + void VclMetafileProcessor2D::processTextHierarchyParagraphPrimitive2D(const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive) + { + const OString aCommentString("XTEXT_EOP"); - break; - } - case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D : - { - const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate); - const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon(); + if(mpPDFExtOutDevData) + { + // emulate data handling from ImpEditEngine::Paint + mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph ); + } - if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) - { - // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points - // per polygon. If there are more, split the polygon in half and call recursively - basegfx::B2DPolygon aLeft, aRight; - splitLinePolygon(rBasePolygon, aLeft, aRight); - rtl::Reference< primitive2d::PolygonHairlinePrimitive2D > xPLeft(new primitive2d::PolygonHairlinePrimitive2D(aLeft, rHairlinePrimitive.getBColor())); - rtl::Reference< primitive2d::PolygonHairlinePrimitive2D > xPRight(new primitive2d::PolygonHairlinePrimitive2D(aRight, rHairlinePrimitive.getBColor())); - - processBasePrimitive2D(*xPLeft.get()); - processBasePrimitive2D(*xPRight.get()); - } - else - { - // direct draw of hairline; use default processing - // support SvtGraphicStroke MetaCommentAction - const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor())); - SvtGraphicStroke* pSvtGraphicStroke = nullptr; + // process recursively and add MetaFile comment + process(rParagraphPrimitive); + mpMetaFile->AddAction(new MetaCommentAction(aCommentString)); - // #i121267# Not needed, does not give better quality compared with - // the MetaActionType::POLYPOLYGON written by RenderPolygonHairlinePrimitive2D - // below - bool bSupportSvtGraphicStroke(false); + if(mpPDFExtOutDevData) + { + // emulate data handling from ImpEditEngine::Paint + mpPDFExtOutDevData->EndStructureElement(); + } + } - if(bSupportSvtGraphicStroke) - { - pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( - rHairlinePrimitive.getB2DPolygon(), - &aLineColor, - nullptr, nullptr, nullptr, nullptr); + void VclMetafileProcessor2D::processTextHierarchyBlockPrimitive2D(const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive) + { + const OString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN"); + const OString aCommentStringB("XTEXT_PAINTSHAPE_END"); - impStartSvtGraphicStroke(pSvtGraphicStroke); - } + // add MetaFile comment, process recursively and add MetaFile comment + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA)); + process(rBlockPrimitive); + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB)); + } - RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false); + void VclMetafileProcessor2D::processTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate) + { + // Adapt evtl. used special DrawMode + const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode()); + adaptTextToFillDrawMode(); - if(bSupportSvtGraphicStroke) - { - impEndSvtGraphicStroke(pSvtGraphicStroke); - } - } - break; - } - case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D : - { - const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate); - const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon(); + // directdraw of text simple portion; use default processing + RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate); - if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) - { - // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points - // per polygon. If there are more, split the polygon in half and call recursively - basegfx::B2DPolygon aLeft, aRight; - splitLinePolygon(rBasePolygon, aLeft, aRight); - rtl::Reference< primitive2d::PolygonStrokePrimitive2D > xPLeft(new primitive2d::PolygonStrokePrimitive2D( - aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute())); - rtl::Reference< primitive2d::PolygonStrokePrimitive2D > xPRight(new primitive2d::PolygonStrokePrimitive2D( - aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute())); - - processBasePrimitive2D(*xPLeft.get()); - processBasePrimitive2D(*xPRight.get()); - } - else - { - mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR); + // restore DrawMode + mpOutputDevice->SetDrawMode(nOriginalDrawMode); - // support SvtGraphicStroke MetaCommentAction - SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( - rBasePolygon, nullptr, - &rStrokePrimitive.getLineAttribute(), - &rStrokePrimitive.getStrokeAttribute(), - nullptr, nullptr); + // #i101169# if(pTextDecoratedCandidate) + { + // support for TEXT_ MetaFile actions only for decorated texts + if(!mxBreakIterator.is()) + { + uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + mxBreakIterator = i18n::BreakIterator::create(xContext); + } - impStartSvtGraphicStroke(pSvtGraphicStroke); - const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute(); + const OUString& rTxt = rTextCandidate.getText(); + const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength()); - // create MetaPolyLineActions, but without LineStyle::Dash - if(basegfx::fTools::more(rLine.getWidth(), 0.0)) + if(nTextLength) + { + const css::lang::Locale& rLocale = rTextCandidate.getLocale(); + const sal_Int32 nTextPosition(rTextCandidate.getTextPosition()); + + sal_Int32 nDone; + sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone)); + css::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, css::i18n::WordType::ANY_WORD, true)); + sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale)); + const OString aCommentStringA("XTEXT_EOC"); + const OString aCommentStringB("XTEXT_EOW"); + const OString aCommentStringC("XTEXT_EOS"); + + for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++) + { + // create the entries for the respective break positions + if(i == nNextCellBreak) + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition)); + nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); + } + if(i == nNextWordBoundary.endPos) { - const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute(); - basegfx::B2DPolyPolygon aHairLinePolyPolygon; - - if(0.0 == rStroke.getFullDotDashLen()) - { - aHairLinePolyPolygon.append(rBasePolygon); - } - else - { - basegfx::utils::applyLineDashing( - rBasePolygon, rStroke.getDotDashArray(), - &aHairLinePolyPolygon, nullptr, rStroke.getFullDotDashLen()); - } - - const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor())); - mpOutputDevice->SetLineColor(Color(aHairlineColor)); - mpOutputDevice->SetFillColor(); - aHairLinePolyPolygon.transform(maCurrentTransformation); - - // use the transformed line width - LineInfo aLineInfo(LineStyle::Solid, basegfx::fround(getTransformedLineWidth(rLine.getWidth()))); - aLineInfo.SetLineJoin(rLine.getLineJoin()); - aLineInfo.SetLineCap(rLine.getLineCap()); - - for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++) - { - const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a)); - - if(aCandidate.count() > 1) - { - const ::tools::Polygon aToolsPolygon(aCandidate); - - mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo)); - } - } + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition)); + nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, css::i18n::WordType::ANY_WORD, true); } - else + if(i == nNextSentenceBreak) { - process(rCandidate); + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition)); + nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale); } + } + } + } + } - impEndSvtGraphicStroke(pSvtGraphicStroke); + void VclMetafileProcessor2D::processPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive) + { + const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon(); - mpOutputDevice->Pop(); - } + if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) + { + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. If there are more, split the polygon in half and call recursively + basegfx::B2DPolygon aLeft, aRight; + splitLinePolygon(rBasePolygon, aLeft, aRight); + rtl::Reference< primitive2d::PolygonHairlinePrimitive2D > xPLeft(new primitive2d::PolygonHairlinePrimitive2D(aLeft, rHairlinePrimitive.getBColor())); + rtl::Reference< primitive2d::PolygonHairlinePrimitive2D > xPRight(new primitive2d::PolygonHairlinePrimitive2D(aRight, rHairlinePrimitive.getBColor())); + + processBasePrimitive2D(*xPLeft.get()); + processBasePrimitive2D(*xPRight.get()); + } + else + { + // direct draw of hairline; use default processing + // support SvtGraphicStroke MetaCommentAction + const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor())); + SvtGraphicStroke* pSvtGraphicStroke = nullptr; - break; + // #i121267# Not needed, does not give better quality compared with + // the MetaActionType::POLYPOLYGON written by RenderPolygonHairlinePrimitive2D + // below + bool bSupportSvtGraphicStroke(false); + + if(bSupportSvtGraphicStroke) + { + pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( + rHairlinePrimitive.getB2DPolygon(), + &aLineColor, + nullptr, nullptr, nullptr, nullptr); + + impStartSvtGraphicStroke(pSvtGraphicStroke); } - case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D : + + RenderPolygonHairlinePrimitive2D(rHairlinePrimitive, false); + + if(bSupportSvtGraphicStroke) + { + impEndSvtGraphicStroke(pSvtGraphicStroke); + } + } + } + + void VclMetafileProcessor2D::processPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive) + { + const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon(); + + if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) + { + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. If there are more, split the polygon in half and call recursively + basegfx::B2DPolygon aLeft, aRight; + splitLinePolygon(rBasePolygon, aLeft, aRight); + rtl::Reference< primitive2d::PolygonStrokePrimitive2D > xPLeft(new primitive2d::PolygonStrokePrimitive2D( + aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute())); + rtl::Reference< primitive2d::PolygonStrokePrimitive2D > xPRight(new primitive2d::PolygonStrokePrimitive2D( + aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute())); + + processBasePrimitive2D(*xPLeft.get()); + processBasePrimitive2D(*xPRight.get()); + } + else + { + mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR); + + // support SvtGraphicStroke MetaCommentAction + SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( + rBasePolygon, nullptr, + &rStrokePrimitive.getLineAttribute(), + &rStrokePrimitive.getStrokeAttribute(), + nullptr, nullptr); + + impStartSvtGraphicStroke(pSvtGraphicStroke); + const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute(); + + // create MetaPolyLineActions, but without LineStyle::Dash + if(basegfx::fTools::more(rLine.getWidth(), 0.0)) { - const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate); - const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon(); + const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute(); + basegfx::B2DPolyPolygon aHairLinePolyPolygon; - if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) + if(0.0 == rStroke.getFullDotDashLen()) { - // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points - // per polygon. If there are more, split the polygon in half and call recursively - basegfx::B2DPolygon aLeft, aRight; - splitLinePolygon(rBasePolygon, aLeft, aRight); - const attribute::LineStartEndAttribute aEmpty; - rtl::Reference< primitive2d::PolygonStrokeArrowPrimitive2D > xPLeft(new primitive2d::PolygonStrokeArrowPrimitive2D( - aLeft, - rStrokeArrowPrimitive.getLineAttribute(), - rStrokeArrowPrimitive.getStrokeAttribute(), - rStrokeArrowPrimitive.getStart(), - aEmpty)); - rtl::Reference< primitive2d::PolygonStrokeArrowPrimitive2D > xPRight(new primitive2d::PolygonStrokeArrowPrimitive2D( - aRight, - rStrokeArrowPrimitive.getLineAttribute(), - rStrokeArrowPrimitive.getStrokeAttribute(), - aEmpty, - rStrokeArrowPrimitive.getEnd())); - - processBasePrimitive2D(*xPLeft.get()); - processBasePrimitive2D(*xPRight.get()); + aHairLinePolyPolygon.append(rBasePolygon); } else { - // support SvtGraphicStroke MetaCommentAction - SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( - rBasePolygon, nullptr, - &rStrokeArrowPrimitive.getLineAttribute(), - &rStrokeArrowPrimitive.getStrokeAttribute(), - &rStrokeArrowPrimitive.getStart(), - &rStrokeArrowPrimitive.getEnd()); - - // write LineGeometry start marker - impStartSvtGraphicStroke(pSvtGraphicStroke); - - // #i116162# When B&W is set as DrawMode, DrawModeFlags::WhiteFill is used - // to let all fills be just white; for lines DrawModeFlags::BlackLine is used - // so all line geometry is supposed to get black. Since in the in-between - // stages of line geometry drawing filled polygons are used (e.g. line - // start/ends) it is necessary to change these drawmodes to preserve - // that lines shall be black; thus change DrawModeFlags::WhiteFill to - // DrawModeFlags::BlackFill during line geometry processing to have line geometry - // parts filled black. - const DrawModeFlags nOldDrawMode(mpOutputDevice->GetDrawMode()); - const bool bDrawmodeChange(nOldDrawMode & DrawModeFlags::WhiteFill && mnSvtGraphicStrokeCount); - - if(bDrawmodeChange) - { - mpOutputDevice->SetDrawMode((nOldDrawMode & ~DrawModeFlags::WhiteFill) | DrawModeFlags::BlackFill); - } + basegfx::utils::applyLineDashing( + rBasePolygon, rStroke.getDotDashArray(), + &aHairLinePolyPolygon, nullptr, rStroke.getFullDotDashLen()); + } - // process sub-line geometry (evtl. filled PolyPolygons) - process(rCandidate); + const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor())); + mpOutputDevice->SetLineColor(Color(aHairlineColor)); + mpOutputDevice->SetFillColor(); + aHairLinePolyPolygon.transform(maCurrentTransformation); - if(bDrawmodeChange) + // use the transformed line width + LineInfo aLineInfo(LineStyle::Solid, basegfx::fround(getTransformedLineWidth(rLine.getWidth()))); + aLineInfo.SetLineJoin(rLine.getLineJoin()); + aLineInfo.SetLineCap(rLine.getLineCap()); + + for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a)); + + if(aCandidate.count() > 1) { - mpOutputDevice->SetDrawMode(nOldDrawMode); - } + const ::tools::Polygon aToolsPolygon(aCandidate); - // write LineGeometry end marker - impEndSvtGraphicStroke(pSvtGraphicStroke); + mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo)); + } } - - break; } - case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D : + else { - // direct draw of transformed BitmapEx primitive; use default processing, but without - // former testing if graphic content is inside discrete local viewport; this is not - // setup for metafile targets (metafile renderer tries to render in logic coordinates, - // the mapping is kept to the OutputDevice for better Metafile recording) - RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate)); - break; + process(rStrokePrimitive); } - case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D : - { - // 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()); - fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon); + impEndSvtGraphicStroke(pSvtGraphicStroke); - SvtGraphicFill* pSvtGraphicFill = nullptr; + mpOutputDevice->Pop(); + } + } - if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) - { - // #121194# Changed implementation and checked usages fo convert to metafile, - // presentation start (uses SvtGraphicFill) and printing. + void VclMetafileProcessor2D::processPolygonStrokeArrowPrimitive2D(const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive) + { + const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon(); - // 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 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] = aTransformScale.getX(); - aTransform.matrix[4] = aTransformScale.getY(); - - // translates are absolute - aTransform.matrix[2] = aTransformPosition.getX(); - aTransform.matrix[5] = aTransformPosition.getY(); - - pSvtGraphicFill = new SvtGraphicFill( - getFillPolyPolygon(aLocalPolyPolygon), - Color(), - 0.0, - SvtGraphicFill::fillEvenOdd, - SvtGraphicFill::fillTexture, - aTransform, - rFillGraphicAttribute.getTiling(), - SvtGraphicFill::hatchSingle, - Color(), - SvtGraphicFill::GradientType::Linear, - Color(), - Color(), - 0, - rFillGraphicAttribute.getGraphic()); - } + if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1)) + { + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. If there are more, split the polygon in half and call recursively + basegfx::B2DPolygon aLeft, aRight; + splitLinePolygon(rBasePolygon, aLeft, aRight); + const attribute::LineStartEndAttribute aEmpty; + rtl::Reference< primitive2d::PolygonStrokeArrowPrimitive2D > xPLeft(new primitive2d::PolygonStrokeArrowPrimitive2D( + aLeft, + rStrokeArrowPrimitive.getLineAttribute(), + rStrokeArrowPrimitive.getStrokeAttribute(), + rStrokeArrowPrimitive.getStart(), + aEmpty)); + rtl::Reference< primitive2d::PolygonStrokeArrowPrimitive2D > xPRight(new primitive2d::PolygonStrokeArrowPrimitive2D( + aRight, + rStrokeArrowPrimitive.getLineAttribute(), + rStrokeArrowPrimitive.getStrokeAttribute(), + aEmpty, + rStrokeArrowPrimitive.getEnd())); + + processBasePrimitive2D(*xPLeft.get()); + processBasePrimitive2D(*xPRight.get()); + } + else + { + // support SvtGraphicStroke MetaCommentAction + SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke( + rBasePolygon, nullptr, + &rStrokeArrowPrimitive.getLineAttribute(), + &rStrokeArrowPrimitive.getStrokeAttribute(), + &rStrokeArrowPrimitive.getStart(), + &rStrokeArrowPrimitive.getEnd()); + + // write LineGeometry start marker + impStartSvtGraphicStroke(pSvtGraphicStroke); + + // #i116162# When B&W is set as DrawMode, DrawModeFlags::WhiteFill is used + // to let all fills be just white; for lines DrawModeFlags::BlackLine is used + // so all line geometry is supposed to get black. Since in the in-between + // stages of line geometry drawing filled polygons are used (e.g. line + // start/ends) it is necessary to change these drawmodes to preserve + // that lines shall be black; thus change DrawModeFlags::WhiteFill to + // DrawModeFlags::BlackFill during line geometry processing to have line geometry + // parts filled black. + const DrawModeFlags nOldDrawMode(mpOutputDevice->GetDrawMode()); + const bool bDrawmodeChange(nOldDrawMode & DrawModeFlags::WhiteFill && mnSvtGraphicStrokeCount); + + if(bDrawmodeChange) + { + mpOutputDevice->SetDrawMode((nOldDrawMode & ~DrawModeFlags::WhiteFill) | DrawModeFlags::BlackFill); + } - // Do use decomposition; encapsulate with SvtGraphicFill - impStartSvtGraphicFill(pSvtGraphicFill); - process(rCandidate); - impEndSvtGraphicFill(pSvtGraphicFill); + // process sub-line geometry (evtl. filled PolyPolygons) + process(rStrokeArrowPrimitive); - break; - } - case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D : + if(bDrawmodeChange) { - // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END - const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate); - const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch(); - basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon()); - - if(aLocalPolyPolygon.getB2DRange() != rHatchCandidate.getDefinitionRange()) - { - // the range which defines the hatch is different from the range of the - // geometry (used for writer frames). This cannot be done calling vcl, thus use - // decomposition here - process(rCandidate); - break; - } + mpOutputDevice->SetDrawMode(nOldDrawMode); + } - // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points - // per polygon. Split polygon until there are less than that - fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon); + // write LineGeometry end marker + impEndSvtGraphicStroke(pSvtGraphicStroke); + } + } - if(rFillHatchAttribute.isFillBackground()) - { - // with fixing #i111954# (see below) the possible background - // fill of a hatched object was lost.Generate a background fill - // primitive and render it - const primitive2d::Primitive2DReference xBackground( - new primitive2d::PolyPolygonColorPrimitive2D( - aLocalPolyPolygon, - rHatchCandidate.getBackgroundColor())); - - process(primitive2d::Primitive2DContainer { xBackground }); - } + void VclMetafileProcessor2D::processPolyPolygonGraphicPrimitive2D(const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate) + { + // need to handle PolyPolygonGraphicPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END + basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon()); - SvtGraphicFill* pSvtGraphicFill = nullptr; - aLocalPolyPolygon.transform(maCurrentTransformation); + fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon); - if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) - { - // re-create a VCL hatch as base data - SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle); + SvtGraphicFill* pSvtGraphicFill = nullptr; - switch(rFillHatchAttribute.getStyle()) - { - default: // attribute::HatchStyle::Single : - { - eHatch = SvtGraphicFill::hatchSingle; - break; - } - case attribute::HatchStyle::Double : - { - eHatch = SvtGraphicFill::hatchDouble; - break; - } - case attribute::HatchStyle::Triple : - { - eHatch = SvtGraphicFill::hatchTriple; - break; - } - } + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + // #121194# Changed implementation and checked usages fo convert to metafile, + // presentation start (uses SvtGraphicFill) and printing. + + // 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 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] = aTransformScale.getX(); + aTransform.matrix[4] = aTransformScale.getY(); + + // translates are absolute + aTransform.matrix[2] = aTransformPosition.getX(); + aTransform.matrix[5] = aTransformPosition.getY(); + + pSvtGraphicFill = new SvtGraphicFill( + getFillPolyPolygon(aLocalPolyPolygon), + Color(), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillTexture, + aTransform, + rFillGraphicAttribute.getTiling(), + SvtGraphicFill::hatchSingle, + Color(), + SvtGraphicFill::GradientType::Linear, + Color(), + Color(), + 0, + rFillGraphicAttribute.getGraphic()); + } - SvtGraphicFill::Transform aTransform; - - // scale - aTransform.matrix[0] *= rFillHatchAttribute.getDistance(); - aTransform.matrix[4] *= rFillHatchAttribute.getDistance(); - - // rotate (was never correct in impgrfll anyways, use correct angle now) - aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle()); - aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle()); - aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle()); - aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle()); - - pSvtGraphicFill = new SvtGraphicFill( - getFillPolyPolygon(aLocalPolyPolygon), - Color(), - 0.0, - SvtGraphicFill::fillEvenOdd, - SvtGraphicFill::fillHatch, - aTransform, - false, - eHatch, - Color(rFillHatchAttribute.getColor()), - SvtGraphicFill::GradientType::Linear, - Color(), - Color(), - 0, - Graphic()); - } + // Do use decomposition; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + process(rBitmapCandidate); + impEndSvtGraphicFill(pSvtGraphicFill); + } - // Do use decomposition; encapsulate with SvtGraphicFill - impStartSvtGraphicFill(pSvtGraphicFill); + void VclMetafileProcessor2D::processPolyPolygonHatchPrimitive2D(const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate) + { + // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END + const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch(); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon()); - // #i111954# do NOT use decomposition, but use direct VCL-command - // process(rCandidate.get2DDecomposition(getViewInformation2D())); - const ::tools::PolyPolygon aToolsPolyPolygon(basegfx::utils::adaptiveSubdivideByAngle(aLocalPolyPolygon)); - const HatchStyle aHatchStyle( - attribute::HatchStyle::Single == rFillHatchAttribute.getStyle() ? HatchStyle::Single : - attribute::HatchStyle::Double == rFillHatchAttribute.getStyle() ? HatchStyle::Double : - HatchStyle::Triple); + if(aLocalPolyPolygon.getB2DRange() != rHatchCandidate.getDefinitionRange()) + { + // the range which defines the hatch is different from the range of the + // geometry (used for writer frames). This cannot be done calling vcl, thus use + // decomposition here + process(rHatchCandidate); + return; + } - mpOutputDevice->DrawHatch(aToolsPolyPolygon, - Hatch(aHatchStyle, - Color(rFillHatchAttribute.getColor()), - basegfx::fround(rFillHatchAttribute.getDistance()), - basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800))); + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon); - impEndSvtGraphicFill(pSvtGraphicFill); + if(rFillHatchAttribute.isFillBackground()) + { + // with fixing #i111954# (see below) the possible background + // fill of a hatched object was lost.Generate a background fill + // primitive and render it + const primitive2d::Primitive2DReference xBackground( + new primitive2d::PolyPolygonColorPrimitive2D( + aLocalPolyPolygon, + rHatchCandidate.getBackgroundColor())); + + process(primitive2d::Primitive2DContainer { xBackground }); + } - break; - } - case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D : - { - basegfx::B2DVector aScale, aTranslate; - double fRotate, fShearX; + SvtGraphicFill* pSvtGraphicFill = nullptr; + aLocalPolyPolygon.transform(maCurrentTransformation); - maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + // re-create a VCL hatch as base data + SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle); - if(!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX)) + switch(rFillHatchAttribute.getStyle()) + { + default: // attribute::HatchStyle::Single : { - // #i121185# When rotation or shear is used, a VCL Gradient cannot be used directly. - // This is because VCL Gradient mechanism does *not* support to rotate the gradient - // with objects and this case is not expressable in a Metafile (and cannot be added - // since the FileFormats used, e.g. *.wmf, do not support it either). - // Such cases happen when a graphic object uses a Metafile as graphic information or - // a fill style definition uses a Metafile. In this cases the graphic content is - // rotated with the graphic or filled object; this is not supported by the target - // format of this conversion renderer - Metafiles. - // To solve this, not a Gradient is written, but the decomposition of this object - // is written to the Metafile. This is the PolyPolygons building the gradient fill. - // These will need more space and time, but the result will be as if the Gradient - // was rotated with the object. - // This mechanism is used by all exporters still not using Primtives (e.g. Print, - // Slideshow, Export rto PDF, export to Picture, ...) but relying on Metafile - // transfers. One more reason to *change* these to primitives. - // BTW: One more example how useful the principles of primitives are; the decomposition - // is by definition a simpler, maybe more expensive representation of the same content. - process(rCandidate); + eHatch = SvtGraphicFill::hatchSingle; break; } - - const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate); - basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon()); - - if(aLocalPolyPolygon.getB2DRange() != rGradientCandidate.getDefinitionRange()) + case attribute::HatchStyle::Double : { - // the range which defines the gradient is different from the range of the - // geometry (used for writer frames). This cannot be done calling vcl, thus use - // decomposition here - process(rCandidate); + eHatch = SvtGraphicFill::hatchDouble; break; } + case attribute::HatchStyle::Triple : + { + eHatch = SvtGraphicFill::hatchTriple; + break; + } + } - // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points - // per polygon. Split polygon until there are less than that - fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon); + SvtGraphicFill::Transform aTransform; + + // scale + aTransform.matrix[0] *= rFillHatchAttribute.getDistance(); + aTransform.matrix[4] *= rFillHatchAttribute.getDistance(); + + // rotate (was never correct in impgrfll anyways, use correct angle now) + aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle()); + aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle()); + aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle()); + aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle()); + + pSvtGraphicFill = new SvtGraphicFill( + getFillPolyPolygon(aLocalPolyPolygon), + Color(), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillHatch, + aTransform, + false, + eHatch, + Color(rFillHatchAttribute.getColor()), + SvtGraphicFill::GradientType::Linear, + Color(), + Color(), + 0, + Graphic()); + } - // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END - // it is safest to use the VCL OutputDevice::DrawGradient method which creates those. - // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon - Gradient aVCLGradient; - impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false); - aLocalPolyPolygon.transform(maCurrentTransformation); + // Do use decomposition; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); - // #i82145# ATM VCL printing of gradients using curved shapes does not work, - // i submitted the bug with the given ID to THB. When that task is fixed it is - // necessary to again remove this subdivision since it decreases possible - // printing quality (not even resolution-dependent for now). THB will tell - // me when that task is fixed in the master - const ::tools::PolyPolygon aToolsPolyPolygon( - getFillPolyPolygon( - basegfx::utils::adaptiveSubdivideByAngle(aLocalPolyPolygon))); + // #i111954# do NOT use decomposition, but use direct VCL-command + // process(rCandidate.get2DDecomposition(getViewInformation2D())); + const ::tools::PolyPolygon aToolsPolyPolygon(basegfx::utils::adaptiveSubdivideByAngle(aLocalPolyPolygon)); + const HatchStyle aHatchStyle( + attribute::HatchStyle::Single == rFillHatchAttribute.getStyle() ? HatchStyle::Single : + attribute::HatchStyle::Double == rFillHatchAttribute.getStyle() ? HatchStyle::Double : + HatchStyle::Triple); + mpOutputDevice->DrawHatch(aToolsPolyPolygon, + Hatch(aHatchStyle, + Color(rFillHatchAttribute.getColor()), + basegfx::fround(rFillHatchAttribute.getDistance()), + basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800))); - // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support - SvtGraphicFill* pSvtGraphicFill = nullptr; + impEndSvtGraphicFill(pSvtGraphicFill); + } - if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) - { - // setup gradient stuff like in impgrfll - SvtGraphicFill::GradientType eGrad(SvtGraphicFill::GradientType::Linear); - - switch(aVCLGradient.GetStyle()) - { - default : // GradientStyle::Linear: - case GradientStyle::Axial: - eGrad = SvtGraphicFill::GradientType::Linear; - break; - case GradientStyle::Radial: - case GradientStyle::Elliptical: - eGrad = SvtGraphicFill::GradientType::Radial; - break; - case GradientStyle::Square: - case GradientStyle::Rect: - eGrad = SvtGraphicFill::GradientType::Rectangular; - break; - } - - pSvtGraphicFill = new SvtGraphicFill( - aToolsPolyPolygon, - Color(), - 0.0, - SvtGraphicFill::fillEvenOdd, - SvtGraphicFill::fillGradient, - SvtGraphicFill::Transform(), - false, - SvtGraphicFill::hatchSingle, - Color(), - eGrad, - aVCLGradient.GetStartColor(), - aVCLGradient.GetEndColor(), - aVCLGradient.GetSteps(), - Graphic()); - } + void VclMetafileProcessor2D::processPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate) + { + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; - // call VCL directly; encapsulate with SvtGraphicFill - impStartSvtGraphicFill(pSvtGraphicFill); - mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient); - impEndSvtGraphicFill(pSvtGraphicFill); + maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX); - break; - } - case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D : + if(!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX)) + { + // #i121185# When rotation or shear is used, a VCL Gradient cannot be used directly. + // This is because VCL Gradient mechanism does *not* support to rotate the gradient + // with objects and this case is not expressable in a Metafile (and cannot be added + // since the FileFormats used, e.g. *.wmf, do not support it either). + // Such cases happen when a graphic object uses a Metafile as graphic information or + // a fill style definition uses a Metafile. In this cases the graphic content is + // rotated with the graphic or filled object; this is not supported by the target + // format of this conversion renderer - Metafiles. + // To solve this, not a Gradient is written, but the decomposition of this object + // is written to the Metafile. This is the PolyPolygons building the gradient fill. + // These will need more space and time, but the result will be as if the Gradient + // was rotated with the object. + // This mechanism is used by all exporters still not using Primtives (e.g. Print, + // Slideshow, Export rto PDF, export to Picture, ...) but relying on Metafile + // transfers. One more reason to *change* these to primitives. + // BTW: One more example how useful the principles of primitives are; the decomposition + // is by definition a simpler, maybe more expensive representation of the same content. + process(rGradientCandidate); + return; + } + + basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon()); + + if(aLocalPolyPolygon.getB2DRange() != rGradientCandidate.getDefinitionRange()) + { + // the range which defines the gradient is different from the range of the + // geometry (used for writer frames). This cannot be done calling vcl, thus use + // decomposition here + process(rGradientCandidate); + return; + } + + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon); + + // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END + // it is safest to use the VCL OutputDevice::DrawGradient method which creates those. + // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon + Gradient aVCLGradient; + impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false); + aLocalPolyPolygon.transform(maCurrentTransformation); + + // #i82145# ATM VCL printing of gradients using curved shapes does not work, + // i submitted the bug with the given ID to THB. When that task is fixed it is + // necessary to again remove this subdivision since it decreases possible + // printing quality (not even resolution-dependent for now). THB will tell + // me when that task is fixed in the master + const ::tools::PolyPolygon aToolsPolyPolygon( + getFillPolyPolygon( + basegfx::utils::adaptiveSubdivideByAngle(aLocalPolyPolygon))); + + + // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support + SvtGraphicFill* pSvtGraphicFill = nullptr; + + if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + // setup gradient stuff like in impgrfll + SvtGraphicFill::GradientType eGrad(SvtGraphicFill::GradientType::Linear); + + switch(aVCLGradient.GetStyle()) { - mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR); - const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate)); - basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); + default : // GradientStyle::Linear: + case GradientStyle::Axial: + eGrad = SvtGraphicFill::GradientType::Linear; + break; + case GradientStyle::Radial: + case GradientStyle::Elliptical: + eGrad = SvtGraphicFill::GradientType::Radial; + break; + case GradientStyle::Square: + case GradientStyle::Rect: + eGrad = SvtGraphicFill::GradientType::Rectangular; + break; + } - // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points - // per polygon. Split polygon until there are less than that - fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon); + pSvtGraphicFill = new SvtGraphicFill( + aToolsPolyPolygon, + Color(), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillGradient, + SvtGraphicFill::Transform(), + false, + SvtGraphicFill::hatchSingle, + Color(), + eGrad, + aVCLGradient.GetStartColor(), + aVCLGradient.GetEndColor(), + aVCLGradient.GetSteps(), + Graphic()); + } - const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); - aLocalPolyPolygon.transform(maCurrentTransformation); + // call VCL directly; encapsulate with SvtGraphicFill + impStartSvtGraphicFill(pSvtGraphicFill); + mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient); + impEndSvtGraphicFill(pSvtGraphicFill); + } - // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support - SvtGraphicFill* pSvtGraphicFill = nullptr; + void VclMetafileProcessor2D::processPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate) + { + mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR); + basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); - // #i121267# Not needed, does not give better quality compared with - // the MetaActionType::POLYPOLYGON written by the DrawPolyPolygon command - // below - bool bSupportSvtGraphicFill(false); + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon); - if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count()) - { - // setup simple color fill stuff like in impgrfll - pSvtGraphicFill = new SvtGraphicFill( - getFillPolyPolygon(aLocalPolyPolygon), - Color(aPolygonColor), - 0.0, - SvtGraphicFill::fillEvenOdd, - SvtGraphicFill::fillSolid, - SvtGraphicFill::Transform(), - false, - SvtGraphicFill::hatchSingle, - Color(), - SvtGraphicFill::GradientType::Linear, - Color(), - Color(), - 0, - Graphic()); - } + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor())); + aLocalPolyPolygon.transform(maCurrentTransformation); - // set line and fill color - mpOutputDevice->SetFillColor(Color(aPolygonColor)); - mpOutputDevice->SetLineColor(); + // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support + SvtGraphicFill* pSvtGraphicFill = nullptr; - // call VCL directly; encapsulate with SvtGraphicFill - if(bSupportSvtGraphicFill) - { - impStartSvtGraphicFill(pSvtGraphicFill); - } + // #i121267# Not needed, does not give better quality compared with + // the MetaActionType::POLYPOLYGON written by the DrawPolyPolygon command + // below + bool bSupportSvtGraphicFill(false); - mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); + if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count()) + { + // setup simple color fill stuff like in impgrfll + pSvtGraphicFill = new SvtGraphicFill( + getFillPolyPolygon(aLocalPolyPolygon), + Color(aPolygonColor), + 0.0, + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillSolid, + SvtGraphicFill::Transform(), + false, + SvtGraphicFill::hatchSingle, + Color(), + SvtGraphicFill::GradientType::Linear, + Color(), + Color(), + 0, + Graphic()); + } - if(bSupportSvtGraphicFill) - { - impEndSvtGraphicFill(pSvtGraphicFill); - } + // set line and fill color + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); - mpOutputDevice->Pop(); - break; - } - case PRIMITIVE2D_ID_MASKPRIMITIVE2D : + // call VCL directly; encapsulate with SvtGraphicFill + if(bSupportSvtGraphicFill) + { + impStartSvtGraphicFill(pSvtGraphicFill); + } + + mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon); + + if(bSupportSvtGraphicFill) + { + impEndSvtGraphicFill(pSvtGraphicFill); + } + + mpOutputDevice->Pop(); + } + + void VclMetafileProcessor2D::processMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate) + { + // mask group. Special handling for MetaFiles. + if(!rMaskCandidate.getChildren().empty()) + { + basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); + + if(aMask.count()) { - // mask group. Special handling for MetaFiles. - const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate); + // prepare new mask polygon and rescue current one + aMask.transform(maCurrentTransformation); + const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon); - if(!rMaskCandidate.getChildren().empty()) + if(maClipPolyPolygon.count()) { - basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask()); + // there is already a clip polygon set; build clipped union of + // current mask polygon and new one + maClipPolyPolygon = basegfx::utils::clipPolyPolygonOnPolyPolygon( + aMask, + maClipPolyPolygon, + true, // #i106516# we want the inside of aMask, not the outside + false); + } + else + { + // use mask directly + maClipPolyPolygon = aMask; + } - if(aMask.count()) - { - // prepare new mask polygon and rescue current one - aMask.transform(maCurrentTransformation); - 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::utils::clipPolyPolygonOnPolyPolygon( - aMask, - maClipPolyPolygon, - true, // #i106516# we want the inside of aMask, not the outside - false); - } - else - { - // use mask directly - maClipPolyPolygon = aMask; - } - - if(maClipPolyPolygon.count()) - { - // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!) - // Removed subdivision and fixed in vcl::Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where - // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there - mpOutputDevice->Push(PushFlags::CLIPREGION); - mpOutputDevice->SetClipRegion(vcl::Region(maClipPolyPolygon)); - - // recursively paint content - // #i121267# Only need to process sub-content when clip polygon is *not* empty. - // If it is empty, the clip is empty and there can be nothing inside. - process(rMaskCandidate.getChildren()); - - // restore VCL clip region - mpOutputDevice->Pop(); - } - - // restore to rescued clip polygon - maClipPolyPolygon = aLastClipPolyPolygon; - } - else - { - // no mask, no clipping. recursively paint content - process(rMaskCandidate.getChildren()); - } + if(maClipPolyPolygon.count()) + { + // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!) + // Removed subdivision and fixed in vcl::Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where + // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there + mpOutputDevice->Push(PushFlags::CLIPREGION); + mpOutputDevice->SetClipRegion(vcl::Region(maClipPolyPolygon)); + + // recursively paint content + // #i121267# Only need to process sub-content when clip polygon is *not* empty. + // If it is empty, the clip is empty and there can be nothing inside. + process(rMaskCandidate.getChildren()); + + // restore VCL clip region + mpOutputDevice->Pop(); } - break; + // restore to rescued clip polygon + maClipPolyPolygon = aLastClipPolyPolygon; } - case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D : + else { - // modified color group. Force output to unified color. Use default pocessing. - RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate)); - break; + // no mask, no clipping. recursively paint content + process(rMaskCandidate.getChildren()); } - case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D : + } + } + + void VclMetafileProcessor2D::processUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate) + { + mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR); + // for metafile: Need to examine what the pure vcl version is doing here actually + // - uses DrawTransparent with metafile for content and a gradient + // - uses DrawTransparent for single PolyPolygons directly. Can be detected by + // checking the content for single PolyPolygonColorPrimitive2D + const primitive2d::Primitive2DContainer& rContent = rUniTransparenceCandidate.getChildren(); + + if(!rContent.empty()) + { + if(0.0 == rUniTransparenceCandidate.getTransparence()) { - mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR); - // for metafile: Need to examine what the pure vcl version is doing here actually - // - uses DrawTransparent with metafile for content and a gradient - // - uses DrawTransparent for single PolyPolygons directly. Can be detected by - // checking the content for single PolyPolygonColorPrimitive2D - const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate); - const primitive2d::Primitive2DContainer& rContent = rUniTransparenceCandidate.getChildren(); + // not transparent at all, use content + process(rUniTransparenceCandidate.getChildren()); + } + else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0) + { + // try to identify a single PolyPolygonColorPrimitive2D in the + // content part of the transparence primitive + const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = nullptr; + static bool bForceToMetafile(false); - if(!rContent.empty()) + if(!bForceToMetafile && 1 == rContent.size()) { - if(0.0 == rUniTransparenceCandidate.getTransparence()) - { - // not transparent at all, use content - process(rUniTransparenceCandidate.getChildren()); - } - else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0) - { - // try to identify a single PolyPolygonColorPrimitive2D in the - // content part of the transparence primitive - const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = nullptr; - static bool bForceToMetafile(false); - - if(!bForceToMetafile && 1 == rContent.size()) - { - const primitive2d::Primitive2DReference xReference(rContent[0]); - pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get()); - } - - // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and - // PolyPolygonGraphicPrimitive2D are derived from PolyPolygonColorPrimitive2D. - // Check also for correct ID to exclude derived implementations - if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID()) - { - // single transparent tools::PolyPolygon identified, use directly - const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); - basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon()); - - // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points - // per polygon. Split polygon until there are less than that - fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon); - - // now transform - aLocalPolyPolygon.transform(maCurrentTransformation); - - // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support - SvtGraphicFill* pSvtGraphicFill = nullptr; - - // #i121267# Not needed, does not give better quality compared with - // the MetaActionType::POLYPOLYGON written by the DrawPolyPolygon command - // below - bool bSupportSvtGraphicFill(false); - - if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count()) - { - // setup simple color with transparence fill stuff like in impgrfll - pSvtGraphicFill = new SvtGraphicFill( - getFillPolyPolygon(aLocalPolyPolygon), - Color(aPolygonColor), - rUniTransparenceCandidate.getTransparence(), - SvtGraphicFill::fillEvenOdd, - SvtGraphicFill::fillSolid, - SvtGraphicFill::Transform(), - false, - SvtGraphicFill::hatchSingle, - Color(), - SvtGraphicFill::GradientType::Linear, - Color(), - Color(), - 0, - Graphic()); - } - - // set line and fill color - const sal_uInt16 nTransPercentVcl(static_cast<sal_uInt16>(basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0))); - mpOutputDevice->SetFillColor(Color(aPolygonColor)); - mpOutputDevice->SetLineColor(); - - // call VCL directly; encapsulate with SvtGraphicFill - if(bSupportSvtGraphicFill) - { - impStartSvtGraphicFill(pSvtGraphicFill); - } - - mpOutputDevice->DrawTransparent( - ::tools::PolyPolygon(aLocalPolyPolygon), - nTransPercentVcl); - - if(bSupportSvtGraphicFill) - { - impEndSvtGraphicFill(pSvtGraphicFill); - } - } - else - { - // save old mfCurrentUnifiedTransparence and set new one - // so that contained SvtGraphicStroke may use the current one - const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence); - // #i105377# paint the content metafile opaque as the transparency gets - // split of into the gradient below - // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence(); - mfCurrentUnifiedTransparence = 0; - - // various content, create content-metafile - GDIMetaFile aContentMetafile; - const ::tools::Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile)); - - // restore mfCurrentUnifiedTransparence; it may have been used - // while processing the sub-content in impDumpToMetaFile - mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence; - - // create uniform VCL gradient for uniform transparency - Gradient aVCLGradient; - const sal_uInt8 nTransPercentVcl(static_cast<sal_uInt8>(basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0))); - const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl); - - aVCLGradient.SetStyle(GradientStyle::Linear); - aVCLGradient.SetStartColor(aTransColor); - aVCLGradient.SetEndColor(aTransColor); - aVCLGradient.SetAngle(0); - aVCLGradient.SetBorder(0); - aVCLGradient.SetOfsX(0); - aVCLGradient.SetOfsY(0); - aVCLGradient.SetStartIntensity(100); - aVCLGradient.SetEndIntensity(100); - aVCLGradient.SetSteps(2); - - // render it to VCL - mpOutputDevice->DrawTransparent( - aContentMetafile, aPrimitiveRectangle.TopLeft(), - aPrimitiveRectangle.GetSize(), aVCLGradient); - } - } + const primitive2d::Primitive2DReference xReference(rContent[0]); + pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get()); } - mpOutputDevice->Pop(); - break; - } - case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D : - { - // for metafile: Need to examine what the pure vcl version is doing here actually - // - uses DrawTransparent with metafile for content and a gradient - // i can detect this here with checking the gradient part for a single - // FillGradientPrimitive2D and reconstruct the gradient. - // If that detection goes wrong, I have to create an transparence-blended bitmap. Eventually - // do that in stripes, else RenderTransparencePrimitive2D may just be used - const primitive2d::TransparencePrimitive2D& rTransparenceCandidate = static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate); - const primitive2d::Primitive2DContainer& rContent = rTransparenceCandidate.getChildren(); - const primitive2d::Primitive2DContainer& rTransparence = rTransparenceCandidate.getTransparence(); - - if(!rContent.empty() && !rTransparence.empty()) + // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and + // PolyPolygonGraphicPrimitive2D are derived from PolyPolygonColorPrimitive2D. + // Check also for correct ID to exclude derived implementations + if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID()) { - // try to identify a single FillGradientPrimitive2D in the - // transparence part of the primitive - const primitive2d::FillGradientPrimitive2D* pFiGradient = nullptr; - static bool bForceToBigTransparentVDev(false); + // single transparent tools::PolyPolygon identified, use directly + const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor())); + basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon()); + + // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points + // per polygon. Split polygon until there are less than that + fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon); - if(!bForceToBigTransparentVDev && 1 == rTransparence.size()) + // now transform + aLocalPolyPolygon.transform(maCurrentTransformation); + + // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support + SvtGraphicFill* pSvtGraphicFill = nullptr; + + // #i121267# Not needed, does not give better quality compared with + // the MetaActionType::POLYPOLYGON written by the DrawPolyPolygon command + // below + bool bSupportSvtGraphicFill(false); + + if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count()) { - const primitive2d::Primitive2DReference xReference(rTransparence[0]); - pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get()); + // setup simple color with transparence fill stuff like in impgrfll + pSvtGraphicFill = new SvtGraphicFill( + getFillPolyPolygon(aLocalPolyPolygon), + Color(aPolygonColor), + rUniTransparenceCandidate.getTransparence(), + SvtGraphicFill::fillEvenOdd, + SvtGraphicFill::fillSolid, + SvtGraphicFill::Transform(), + false, + SvtGraphicFill::hatchSingle, + Color(), + SvtGraphicFill::GradientType::Linear, + Color(), + Color(), + 0, + Graphic()); } - // Check also for correct ID to exclude derived implementations - if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID()) + // set line and fill color + const sal_uInt16 nTransPercentVcl(static_cast<sal_uInt16>(basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0))); + mpOutputDevice->SetFillColor(Color(aPolygonColor)); + mpOutputDevice->SetLineColor(); + + // call VCL directly; encapsulate with SvtGraphicFill + if(bSupportSvtGraphicFill) { - // various content, create content-metafile - GDIMetaFile aContentMetafile; - const ::tools::Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile)); - - // re-create a VCL-gradient from FillGradientPrimitive2D - Gradient aVCLGradient; - impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true); - - // render it to VCL - mpOutputDevice->DrawTransparent( - aContentMetafile, aPrimitiveRectangle.TopLeft(), - aPrimitiveRectangle.GetSize(), aVCLGradient); + impStartSvtGraphicFill(pSvtGraphicFill); } - else + + mpOutputDevice->DrawTransparent( + ::tools::PolyPolygon(aLocalPolyPolygon), + nTransPercentVcl); + + if(bSupportSvtGraphicFill) { - // sub-transparence group. Draw to VDev first. - // this may get refined to tiling when resolution is too big here - - // need to avoid switching off MapMode stuff here; maybe need another - // tooling class, cannot just do the same as with the pixel renderer. - // Need to experiment... - - // Okay, basic implementation finished and tested. The DPI stuff was hard - // and not easy to find out that it's needed. - // Since this will not yet happen normally (as long as no one constructs - // transparence primitives with non-trivial transparence content) i will for now not - // refine to tiling here. - - basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D())); - aViewRange.transform(maCurrentTransformation); - const ::tools::Rectangle aRectLogic( - static_cast<sal_Int32>(floor(aViewRange.getMinX())), static_cast<sal_Int32>(floor(aViewRange.getMinY())), - static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), static_cast<sal_Int32>(ceil(aViewRange.getMaxY()))); - const ::tools::Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic)); - Size aSizePixel(aRectPixel.GetSize()); - const Point aEmptyPoint; - ScopedVclPtrInstance< VirtualDevice > aBufferDevice; - const sal_uInt32 nMaxQuadratPixels(500000); - const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight()); - double fReduceFactor(1.0); - - if(nViewVisibleArea > nMaxQuadratPixels) - { - // reduce render size - fReduceFactor = sqrt(double(nMaxQuadratPixels) / static_cast<double>(nViewVisibleArea)); - aSizePixel = Size(basegfx::fround(static_cast<double>(aSizePixel.getWidth()) * fReduceFactor), - basegfx::fround(static_cast<double>(aSizePixel.getHeight()) * fReduceFactor)); - } - - if(aBufferDevice->SetOutputSizePixel(aSizePixel)) - { - // create and set MapModes for target devices - MapMode aNewMapMode(mpOutputDevice->GetMapMode()); - aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top())); - aBufferDevice->SetMapMode(aNewMapMode); - - // prepare view transformation for target renderers - // ATTENTION! Need to apply another scaling because of the potential DPI differences - // between Printer and VDev (mpOutputDevice and aBufferDevice here). - // To get the DPI, LogicToPixel from (1,1) from MapUnit::MapInch needs to be used. - basegfx::B2DHomMatrix aViewTransform(aBufferDevice->GetViewTransformation()); - const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch))); - const Size aDPINew(aBufferDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch))); - const double fDPIXChange(static_cast<double>(aDPIOld.getWidth()) / static_cast<double>(aDPINew.getWidth())); - const double fDPIYChange(static_cast<double>(aDPIOld.getHeight()) / static_cast<double>(aDPINew.getHeight())); - - if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0)) - { - aViewTransform.scale(fDPIXChange, fDPIYChange); - } - - // also take scaling from Size reduction into account - if(!basegfx::fTools::equal(fReduceFactor, 1.0)) - { - aViewTransform.scale(fReduceFactor, fReduceFactor); - } - - // create view information and pixel renderer. Reuse known ViewInformation - // except new transformation and range - const geometry::ViewInformation2D aViewInfo( - getViewInformation2D().getObjectTransformation(), - aViewTransform, - aViewRange, - getViewInformation2D().getVisualizedPage(), - getViewInformation2D().getViewTime(), - getViewInformation2D().getExtendedInformationSequence()); - - VclPixelProcessor2D aBufferProcessor(aViewInfo, *aBufferDevice.get()); - - // draw content using pixel renderer - aBufferProcessor.process(rContent); - const Bitmap aBmContent(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel)); - - // draw transparence using pixel renderer - aBufferDevice->Erase(); - aBufferProcessor.process(rTransparence); - const AlphaMask aBmAlpha(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel)); - - // paint - mpOutputDevice->DrawBitmapEx( - aRectLogic.TopLeft(), - aRectLogic.GetSize(), - BitmapEx(aBmContent, aBmAlpha)); - } + impEndSvtGraphicFill(pSvtGraphicFill); } } - - break; - } - case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D : - { - // use default transform group pocessing - RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate)); - break; - } - case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D : - { - // new XDrawPage for ViewInformation2D - RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate)); - break; + else + { + // save old mfCurrentUnifiedTransparence and set new one + // so that contained SvtGraphicStroke may use the current one + const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence); + // #i105377# paint the content metafile opaque as the transparency gets + // split of into the gradient below + // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence(); + mfCurrentUnifiedTransparence = 0; + + // various content, create content-metafile + GDIMetaFile aContentMetafile; + const ::tools::Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile)); + + // restore mfCurrentUnifiedTransparence; it may have been used + // while processing the sub-content in impDumpToMetaFile + mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence; + + // create uniform VCL gradient for uniform transparency + Gradient aVCLGradient; + const sal_uInt8 nTransPercentVcl(static_cast<sal_uInt8>(basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0))); + const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl); + + aVCLGradient.SetStyle(GradientStyle::Linear); + aVCLGradient.SetStartColor(aTransColor); + aVCLGradient.SetEndColor(aTransColor); + aVCLGradient.SetAngle(0); + aVCLGradient.SetBorder(0); + aVCLGradient.SetOfsX(0); + aVCLGradient.SetOfsY(0); + aVCLGradient.SetStartIntensity(100); + aVCLGradient.SetEndIntensity(100); + aVCLGradient.SetSteps(2); + + // render it to VCL + mpOutputDevice->DrawTransparent( + aContentMetafile, aPrimitiveRectangle.TopLeft(), + aPrimitiveRectangle.GetSize(), aVCLGradient); + } } - case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D : + } + + mpOutputDevice->Pop(); + } + + void VclMetafileProcessor2D::processTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransparenceCandidate) + { + // for metafile: Need to examine what the pure vcl version is doing here actually + // - uses DrawTransparent with metafile for content and a gradient + // i can detect this here with checking the gradient part for a single + // FillGradientPrimitive2D and reconstruct the gradient. + // If that detection goes wrong, I have to create an transparence-blended bitmap. Eventually + // do that in stripes, else RenderTransparencePrimitive2D may just be used + const primitive2d::Primitive2DContainer& rContent = rTransparenceCandidate.getChildren(); + const primitive2d::Primitive2DContainer& rTransparence = rTransparenceCandidate.getTransparence(); + + if(!rContent.empty() && !rTransparence.empty()) + { + // try to identify a single FillGradientPrimitive2D in the + // transparence part of the primitive + const primitive2d::FillGradientPrimitive2D* pFiGradient = nullptr; + static bool bForceToBigTransparentVDev(false); + + if(!bForceToBigTransparentVDev && 1 == rTransparence.size()) { - // use default marker array pocessing - RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate)); - break; + const primitive2d::Primitive2DReference xReference(rTransparence[0]); + pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get()); } - case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D : + + // Check also for correct ID to exclude derived implementations + if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID()) { - // use default point array pocessing - RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate)); - break; + // various content, create content-metafile + GDIMetaFile aContentMetafile; + const ::tools::Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile)); + + // re-create a VCL-gradient from FillGradientPrimitive2D + Gradient aVCLGradient; + impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true); + + // render it to VCL + mpOutputDevice->DrawTransparent( + aContentMetafile, aPrimitiveRectangle.TopLeft(), + aPrimitiveRectangle.GetSize(), aVCLGradient); } - case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D : + else { - // structured tag primitive - const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate = static_cast< const primitive2d::StructureTagPrimitive2D& >(rCandidate); - const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement()); - const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement); - - if(mpPDFExtOutDevData && bTagUsed) + // sub-transparence group. Draw to VDev first. + // this may get refined to tiling when resolution is too big here + + // need to avoid switching off MapMode stuff here; maybe need another + // tooling class, cannot just do the same as with the pixel renderer. + // Need to experiment... + + // Okay, basic implementation finished and tested. The DPI stuff was hard + // and not easy to find out that it's needed. + // Since this will not yet happen normally (as long as no one constructs + // transparence primitives with non-trivial transparence content) i will for now not + // refine to tiling here. + + basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D())); + aViewRange.transform(maCurrentTransformation); + const ::tools::Rectangle aRectLogic( + static_cast<sal_Int32>(floor(aViewRange.getMinX())), static_cast<sal_Int32>(floor(aViewRange.getMinY())), + static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), static_cast<sal_Int32>(ceil(aViewRange.getMaxY()))); + const ::tools::Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic)); + Size aSizePixel(aRectPixel.GetSize()); + const Point aEmptyPoint; + ScopedVclPtrInstance< VirtualDevice > aBufferDevice; + const sal_uInt32 nMaxQuadratPixels(500000); + const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight()); + double fReduceFactor(1.0); + + if(nViewVisibleArea > nMaxQuadratPixels) { - // write start tag - mpPDFExtOutDevData->BeginStructureElement(rTagElement); + // reduce render size + fReduceFactor = sqrt(double(nMaxQuadratPixels) / static_cast<double>(nViewVisibleArea)); + aSizePixel = Size(basegfx::fround(static_cast<double>(aSizePixel.getWidth()) * fReduceFactor), + basegfx::fround(static_cast<double>(aSizePixel.getHeight()) * fReduceFactor)); } - // process children normally - process(rStructureTagCandidate.getChildren()); - - if(mpPDFExtOutDevData && bTagUsed) + if(aBufferDevice->SetOutputSizePixel(aSizePixel)) { - // write end tag - mpPDFExtOutDevData->EndStructureElement(); - } + // create and set MapModes for target devices + MapMode aNewMapMode(mpOutputDevice->GetMapMode()); + aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top())); + aBufferDevice->SetMapMode(aNewMapMode); + + // prepare view transformation for target renderers + // ATTENTION! Need to apply another scaling because of the potential DPI differences + // between Printer and VDev (mpOutputDevice and aBufferDevice here). + // To get the DPI, LogicToPixel from (1,1) from MapUnit::MapInch needs to be used. + basegfx::B2DHomMatrix aViewTransform(aBufferDevice->GetViewTransformation()); + const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch))); + const Size aDPINew(aBufferDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch))); + const double fDPIXChange(static_cast<double>(aDPIOld.getWidth()) / static_cast<double>(aDPINew.getWidth())); + const double fDPIYChange(static_cast<double>(aDPIOld.getHeight()) / static_cast<double>(aDPINew.getHeight())); + + if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0)) + { + aViewTransform.scale(fDPIXChange, fDPIYChange); + } - break; - } - case PRIMITIVE2D_ID_EPSPRIMITIVE2D : - { - RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate)); - break; - } - default : - { - // process recursively - process(rCandidate); - break; + // also take scaling from Size reduction into account + if(!basegfx::fTools::equal(fReduceFactor, 1.0)) + { + aViewTransform.scale(fReduceFactor, fReduceFactor); + } + + // create view information and pixel renderer. Reuse known ViewInformation + // except new transformation and range + const geometry::ViewInformation2D aViewInfo( + getViewInformation2D().getObjectTransformation(), + aViewTransform, + aViewRange, + getViewInformation2D().getVisualizedPage(), + getViewInformation2D().getViewTime(), + getViewInformation2D().getExtendedInformationSequence()); + + VclPixelProcessor2D aBufferProcessor(aViewInfo, *aBufferDevice.get()); + + // draw content using pixel renderer + aBufferProcessor.process(rContent); + const Bitmap aBmContent(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel)); + + // draw transparence using pixel renderer + aBufferDevice->Erase(); + aBufferProcessor.process(rTransparence); + const AlphaMask aBmAlpha(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel)); + + // paint + mpOutputDevice->DrawBitmapEx( + aRectLogic.TopLeft(), + aRectLogic.GetSize(), + BitmapEx(aBmContent, aBmAlpha)); + } } } } + + void VclMetafileProcessor2D::processStructureTagPrimitive2D(const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate) + { + // structured tag primitive + const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement()); + const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement); + + if(mpPDFExtOutDevData && bTagUsed) + { + // write start tag + mpPDFExtOutDevData->BeginStructureElement(rTagElement); + } + + // process children normally + process(rStructureTagCandidate.getChildren()); + + if(mpPDFExtOutDevData && bTagUsed) + { + // write end tag + mpPDFExtOutDevData->EndStructureElement(); + } + } + } // end of namespace processor2d } // end of namespace drawinglayer diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx index 122cafa47978..65007b487727 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx @@ -47,6 +47,28 @@ namespace drawinglayer { namespace attribute { class LineStartEndAttribute; }} +namespace drawinglayer { namespace primitive2d { + class GraphicPrimitive2D; + class ControlPrimitive2D; + class TextHierarchyFieldPrimitive2D; + class TextHierarchyLinePrimitive2D; + class TextHierarchyBulletPrimitive2D; + class TextHierarchyParagraphPrimitive2D; + class TextHierarchyBlockPrimitive2D; + class TextSimplePortionPrimitive2D; + class PolygonHairlinePrimitive2D; + class PolygonStrokePrimitive2D; + class PolygonStrokeArrowPrimitive2D; + class PolyPolygonGraphicPrimitive2D; + class PolyPolygonHatchPrimitive2D; + class PolyPolygonGradientPrimitive2D; + class PolyPolygonColorPrimitive2D; + class MaskPrimitive2D; + class UnifiedTransparencePrimitive2D; + class TransparencePrimitive2D; + class StructureTagPrimitive2D; +}} + namespace basegfx { class BColor; } @@ -91,6 +113,26 @@ namespace drawinglayer void impStartSvtGraphicStroke(SvtGraphicStroke const * pSvtGraphicStroke); void impEndSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke); + void processGraphicPrimitive2D(const primitive2d::GraphicPrimitive2D& rGraphicPrimitive); + void processControlPrimitive2D(const primitive2d::ControlPrimitive2D& rControlPrimitive); + void processTextHierarchyFieldPrimitive2D(const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive); + void processTextHierarchyLinePrimitive2D(const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive); + void processTextHierarchyBulletPrimitive2D(const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive); + void processTextHierarchyParagraphPrimitive2D(const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive); + void processTextHierarchyBlockPrimitive2D(const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive); + void processTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate); + void processPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive); + void processPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive); + void processPolygonStrokeArrowPrimitive2D(const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive); + void processPolyPolygonGraphicPrimitive2D(const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate); + void processPolyPolygonHatchPrimitive2D(const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate); + void processPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate); + void processPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate); + void processMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate); + void processUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate); + void processTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransparenceCandidate); + void processStructureTagPrimitive2D(const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate); + /// Convert the fWidth to the same space as its coordinates. double getTransformedLineWidth( double fWidth ) const; |