Change-Id: Ib40241eb794607154ae52f8aa68fbf5ea5e944af Reviewed-on: https://gerrit.libreoffice.org/39551 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
300 lines
11 KiB
C++
Executable File
300 lines
11 KiB
C++
Executable File
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <com/sun/star/rendering/PathCapType.hpp>
|
|
#include <com/sun/star/rendering/PathJoinType.hpp>
|
|
#include <com/sun/star/rendering/TexturingMode.hpp>
|
|
#include <com/sun/star/rendering/XCanvas.hpp>
|
|
#include <basegfx/tools/canvastools.hxx>
|
|
#include <basegfx/tools/gradienttools.hxx>
|
|
#include <basegfx/tools/tools.hxx>
|
|
#include <basegfx/numeric/ftools.hxx>
|
|
#include <basegfx/point/b2dpoint.hxx>
|
|
#include <basegfx/vector/b2dsize.hxx>
|
|
#include <basegfx/range/b2drange.hxx>
|
|
#include <basegfx/range/b2drectangle.hxx>
|
|
#include <basegfx/polygon/b2dlinegeometry.hxx>
|
|
#include <basegfx/polygon/b2dpolygon.hxx>
|
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
|
#include <basegfx/polygon/b2dpolypolygon.hxx>
|
|
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
|
#include <vcl/canvastools.hxx>
|
|
#include <implrenderer.hxx>
|
|
#include <emfppen.hxx>
|
|
#include <emfpcustomlinecap.hxx>
|
|
|
|
using namespace ::com::sun::star;
|
|
using namespace ::basegfx;
|
|
|
|
namespace cppcanvas
|
|
{
|
|
namespace internal
|
|
{
|
|
|
|
enum EmfPlusPenData
|
|
{
|
|
PenDataTransform = 0x00000001,
|
|
PenDataStartCap = 0x00000002,
|
|
PenDataEndCap = 0x00000004,
|
|
PenDataJoin = 0x00000008,
|
|
PenDataMiterLimit = 0x00000010,
|
|
PenDataLineStyle = 0x00000020,
|
|
PenDataDashedLineCap = 0x00000040,
|
|
PenDataDashedLineOffset = 0x00000080,
|
|
PenDataDashedLine = 0x00000100,
|
|
PenDataNonCenter = 0x00000200,
|
|
PenDataCompoundLine = 0x00000400,
|
|
PenDataCustomStartCap = 0x00000800,
|
|
PenDataCustomEndCap = 0x00001000
|
|
};
|
|
|
|
const sal_Int32 EmfPlusLineStyleSolid = 0x00000000;
|
|
const sal_Int32 EmfPlusLineStyleDash = 0x00000001;
|
|
const sal_Int32 EmfPlusLineStyleDot = 0x00000002;
|
|
const sal_Int32 EmfPlusLineStyleDashDot = 0x00000003;
|
|
const sal_Int32 EmfPlusLineStyleDashDotDot = 0x00000004;
|
|
const sal_Int32 EmfPlusLineStyleCustom = 0x00000005;
|
|
|
|
EMFPPen::EMFPPen()
|
|
: EMFPBrush()
|
|
, penWidth(0.0)
|
|
, startCap(0)
|
|
, endCap(0)
|
|
, lineJoin(0)
|
|
, mitterLimit(0.0)
|
|
, dashStyle(0)
|
|
, dashCap(0)
|
|
, dashOffset(0.0)
|
|
, alignment(0)
|
|
, customStartCapLen(0)
|
|
, customStartCap(nullptr)
|
|
, customEndCapLen(0)
|
|
, customEndCap(nullptr)
|
|
{
|
|
}
|
|
|
|
EMFPPen::~EMFPPen()
|
|
{
|
|
delete customStartCap;
|
|
delete customEndCap;
|
|
}
|
|
|
|
void EMFPPen::SetStrokeWidth(rendering::StrokeAttributes& rStrokeAttributes, ImplRenderer& rR, const OutDevState& rState)
|
|
{
|
|
// If a zero width is specified, a minimum value is used, which is determined by the units.
|
|
//TODO Add support for other units than Pixel
|
|
rStrokeAttributes.StrokeWidth = fabs((rState.mapModeTransform * rR.MapSize(penWidth == 0.0 ? 0.05 : penWidth, 0)).getLength());
|
|
|
|
// tdf#31814 Based on observation of different EMF+ files (eg. exported by ChemDraw),
|
|
// there is minimal value of line width
|
|
if (rStrokeAttributes.StrokeWidth < 1.0)
|
|
{
|
|
rStrokeAttributes.StrokeWidth = 1.0;
|
|
}
|
|
}
|
|
|
|
/// Convert stroke caps between EMF+ and rendering API
|
|
sal_Int8 EMFPPen::lcl_convertStrokeCap(sal_uInt32 nEmfStroke)
|
|
{
|
|
switch (nEmfStroke)
|
|
{
|
|
case EmfPlusLineCapTypeSquare: return rendering::PathCapType::SQUARE;
|
|
case EmfPlusLineCapTypeRound: return rendering::PathCapType::ROUND;
|
|
}
|
|
|
|
// we have no mapping for EmfPlusLineCapTypeTriangle = 0x00000003,
|
|
// so return BUTT always
|
|
return rendering::PathCapType::BUTT;
|
|
}
|
|
|
|
sal_Int8 EMFPPen::lcl_convertLineJoinType(sal_uInt32 nEmfLineJoin)
|
|
{
|
|
switch (nEmfLineJoin)
|
|
{
|
|
case EmfPlusLineJoinTypeMiter: // fall-through
|
|
case EmfPlusLineJoinTypeMiterClipped: return rendering::PathJoinType::MITER;
|
|
case EmfPlusLineJoinTypeBevel: return rendering::PathJoinType::BEVEL;
|
|
case EmfPlusLineJoinTypeRound: return rendering::PathJoinType::ROUND;
|
|
}
|
|
assert(false); // Line Join type isn't in specification.
|
|
return 0;
|
|
}
|
|
|
|
|
|
void EMFPPen::SetStrokeAttributes(rendering::StrokeAttributes& rStrokeAttributes)
|
|
{
|
|
rStrokeAttributes.JoinType = lcl_convertLineJoinType(lineJoin);
|
|
|
|
if (dashStyle != EmfPlusLineStyleSolid)
|
|
{
|
|
const float dash[] = { 3, 3 };
|
|
const float dot[] = { 1, 3 };
|
|
const float dashdot[] = { 3, 3, 1, 3 };
|
|
const float dashdotdot[] = { 3, 3, 1, 3, 1, 3 };
|
|
|
|
sal_Int32 nLen = 0;
|
|
const float *pPattern = nullptr;
|
|
switch (dashStyle)
|
|
{
|
|
case EmfPlusLineStyleDash: nLen = SAL_N_ELEMENTS(dash); pPattern = dash; break;
|
|
case EmfPlusLineStyleDot: nLen = SAL_N_ELEMENTS(dot); pPattern = dot; break;
|
|
case EmfPlusLineStyleDashDot: nLen = SAL_N_ELEMENTS(dashdot); pPattern = dashdot; break;
|
|
case EmfPlusLineStyleDashDotDot: nLen = SAL_N_ELEMENTS(dashdotdot); pPattern = dashdotdot; break;
|
|
case EmfPlusLineStyleCustom: nLen = dashPattern.size(); pPattern = dashPattern.data(); break;
|
|
}
|
|
if (nLen > 0)
|
|
{
|
|
uno::Sequence<double> aDashArray(nLen);
|
|
for (int i = 0; i < nLen; ++i)
|
|
aDashArray[i] = pPattern[i];
|
|
|
|
rStrokeAttributes.DashArray = aDashArray;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EMFPPen::Read(SvStream& s, ImplRenderer& rR)
|
|
{
|
|
sal_uInt32 graphicsVersion, penType, penDataFlags, penUnit;
|
|
int i;
|
|
|
|
s.ReadUInt32(graphicsVersion).ReadUInt32(penType).ReadUInt32(penDataFlags).ReadUInt32(penUnit).ReadFloat(penWidth);
|
|
|
|
SAL_INFO("cppcanvas.emf", "EMF+\tpen");
|
|
SAL_INFO("cppcanvas.emf", "EMF+\t graphics version: 0x" << std::hex << graphicsVersion << " type (must be set to zero): " << penType <<
|
|
" pen data flags: 0x" << penDataFlags << " unit: " << penUnit << " width: " << std::dec << penWidth);
|
|
|
|
if (penDataFlags & PenDataTransform)
|
|
ReadXForm(s, pen_transformation);
|
|
|
|
if (penDataFlags & PenDataStartCap)
|
|
{
|
|
s.ReadInt32(startCap);
|
|
SAL_INFO("cppcanvas.emf", "EMF+\t\tstartCap: 0x" << std::hex << startCap);
|
|
}
|
|
else
|
|
startCap = 0;
|
|
|
|
if (penDataFlags & PenDataEndCap)
|
|
{
|
|
s.ReadInt32(endCap);
|
|
SAL_INFO("cppcanvas.emf", "EMF+\t\tendCap: 0x" << std::hex << endCap);
|
|
}
|
|
else
|
|
endCap = 0;
|
|
|
|
if (penDataFlags & PenDataJoin)
|
|
s.ReadInt32(lineJoin);
|
|
else
|
|
lineJoin = 0;
|
|
|
|
if (penDataFlags & PenDataMiterLimit)
|
|
s.ReadFloat(mitterLimit);
|
|
else
|
|
mitterLimit = 0;
|
|
|
|
if (penDataFlags & PenDataLineStyle)
|
|
{
|
|
s.ReadInt32(dashStyle);
|
|
SAL_INFO("cppcanvas.emf", "EMF+\t\tdashStyle: 0x" << std::hex << dashStyle);
|
|
}
|
|
else
|
|
dashStyle = 0;
|
|
|
|
if (penDataFlags & PenDataDashedLineCap)
|
|
s.ReadInt32(dashCap);
|
|
else
|
|
dashCap = 0;
|
|
|
|
if (penDataFlags & PenDataDashedLineOffset)
|
|
s.ReadFloat(dashOffset);
|
|
else
|
|
dashOffset = 0;
|
|
|
|
if (penDataFlags & PenDataDashedLine)
|
|
{
|
|
dashStyle = EmfPlusLineStyleCustom;
|
|
sal_Int32 dashPatternLen;
|
|
|
|
s.ReadInt32(dashPatternLen);
|
|
SAL_INFO("cppcanvas.emf", "EMF+\t\tdashPatternLen: " << dashPatternLen);
|
|
|
|
if (dashPatternLen<0 || sal_uInt32(dashPatternLen)>SAL_MAX_INT32 / sizeof(float))
|
|
dashPatternLen = SAL_MAX_INT32 / sizeof(float);
|
|
dashPattern.resize( dashPatternLen );
|
|
for (i = 0; i < dashPatternLen; i++)
|
|
{
|
|
s.ReadFloat(dashPattern[i]);
|
|
SAL_INFO("cppcanvas.emf", "EMF+\t\t\tdashPattern[" << i << "]: " << dashPattern[i]);
|
|
}
|
|
}
|
|
|
|
if (penDataFlags & PenDataNonCenter)
|
|
s.ReadInt32(alignment);
|
|
else
|
|
alignment = 0;
|
|
|
|
if (penDataFlags & PenDataCompoundLine)
|
|
{
|
|
sal_Int32 compoundArrayLen;
|
|
s.ReadInt32(compoundArrayLen);
|
|
if (compoundArrayLen<0 || sal_uInt32(compoundArrayLen)>SAL_MAX_INT32 / sizeof(float))
|
|
compoundArrayLen = SAL_MAX_INT32 / sizeof(float);
|
|
compoundArray.resize(compoundArrayLen);
|
|
for (i = 0; i < compoundArrayLen; i++)
|
|
s.ReadFloat(compoundArray[i]);
|
|
}
|
|
|
|
if (penDataFlags & PenDataCustomStartCap)
|
|
{
|
|
s.ReadInt32(customStartCapLen);
|
|
SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomStartCapLen: " << customStartCapLen);
|
|
sal_uInt64 const pos = s.Tell();
|
|
|
|
customStartCap = new EMFPCustomLineCap();
|
|
customStartCap->Read(s, rR);
|
|
|
|
// maybe we don't read everything yet, play it safe ;-)
|
|
s.Seek(pos + customStartCapLen);
|
|
}
|
|
else
|
|
customStartCapLen = 0;
|
|
|
|
if (penDataFlags & PenDataCustomEndCap)
|
|
{
|
|
s.ReadInt32(customEndCapLen);
|
|
SAL_INFO("cppcanvas.emf", "EMF+\t\tcustomEndCapLen: " << customEndCapLen);
|
|
sal_uInt64 const pos = s.Tell();
|
|
|
|
customEndCap = new EMFPCustomLineCap();
|
|
customEndCap->Read(s, rR);
|
|
|
|
// maybe we don't read everything yet, play it safe ;-)
|
|
s.Seek(pos + customEndCapLen);
|
|
}
|
|
else
|
|
customEndCapLen = 0;
|
|
|
|
EMFPBrush::Read(s, rR);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|