Files
libreoffice/cppcanvas/source/mtfrenderer/emfppath.cxx
Bartosz Kosiorek 5726633455 tdf#39053 EMF+ Draw an extra line between the last point and the first point.
The EmfPlusDrawlLines record specifies drawing a series of connected lines.
Bit 0x2000 indicates whether to draw an extra line between the last point
and the first point, to close the shape.
In this commit support of additional line which close shape was added.

Change-Id: I47ae3d8003cbfdd5b8ff5ba78e1ebe10f97af04b
Reviewed-on: https://gerrit.libreoffice.org/36317
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
2017-04-13 18:30:37 +02:00

196 lines
8.2 KiB
C++

/* -*- 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 <emfppath.hxx>
using namespace ::com::sun::star;
using namespace ::basegfx;
namespace cppcanvas
{
namespace internal
{
EMFPPath::EMFPPath (sal_Int32 _nPoints, bool bLines)
{
if( _nPoints<0 || sal_uInt32(_nPoints)>SAL_MAX_INT32/(2*sizeof(float)) )
_nPoints = SAL_MAX_INT32/(2*sizeof(float));
nPoints = _nPoints;
pPoints = new float [nPoints*2];
if (!bLines)
pPointTypes = new sal_uInt8 [_nPoints];
else
pPointTypes = nullptr;
}
EMFPPath::~EMFPPath ()
{
delete [] pPoints;
delete [] pPointTypes;
}
// TODO: remove rR argument when debug code is not longer needed
void EMFPPath::Read (SvStream& s, sal_uInt32 pathFlags, ImplRenderer& rR)
{
for (int i = 0; i < nPoints; i ++) {
if (pathFlags & 0x4000) {
// EMFPlusPoint: stored in signed short 16bit integer format
sal_Int16 x, y;
s.ReadInt16( x ).ReadInt16( y );
SAL_INFO ("cppcanvas.emf", "EMF+\tEMFPlusPoint [x,y]: " << x << "," << y);
pPoints [i*2] = x;
pPoints [i*2 + 1] = y;
} else if (!(pathFlags & 0xC000)) {
// EMFPlusPointF: stored in Single (float) format
s.ReadFloat( pPoints [i*2] ).ReadFloat( pPoints [i*2 + 1] );
SAL_INFO ("cppcanvas.emf", "EMF+\tEMFPlusPointF [x,y]: " << pPoints [i*2] << "," << pPoints [i*2 + 1]);
} else { //if (pathFlags & 0x8000)
// EMFPlusPointR: points are stored in EMFPlusInteger7 or
// EMFPlusInteger15 objects, see section 2.2.2.21/22
SAL_INFO("cppcanvas.emf", "EMF+\t\tTODO - parse EMFPlusPointR object (section 2.2.1.6)");
}
}
if (pPointTypes)
for (int i = 0; i < nPoints; i ++) {
s.ReadUChar( pPointTypes [i] );
SAL_INFO ("cppcanvas.emf", "EMF+\tpoint type: " << (int)pPointTypes [i]);
}
aPolygon.clear ();
#if OSL_DEBUG_LEVEL > 1
const ::basegfx::B2DRectangle aBounds (::basegfx::tools::getRange (GetPolygon (rR)));
SAL_INFO ("cppcanvas.emf",
"EMF+\tpolygon bounding box: " << aBounds.getMinX () << "," << aBounds.getMinY () << aBounds.getWidth () << "x" << aBounds.getHeight () << " (mapped)");
#else
(void) rR; // avoid warnings
#endif
}
::basegfx::B2DPolyPolygon& EMFPPath::GetPolygon (ImplRenderer& rR, bool bMapIt, bool bAddLineToCloseShape)
{
::basegfx::B2DPolygon polygon;
aPolygon.clear ();
int last_normal = 0, p = 0;
::basegfx::B2DPoint prev, mapped;
bool hasPrev = false;
for (int i = 0; i < nPoints; i ++) {
if (p && pPointTypes && (pPointTypes [i] == 0)) {
aPolygon.append (polygon);
last_normal = i;
p = 0;
polygon.clear ();
}
if (bMapIt)
mapped = rR.Map (pPoints [i*2], pPoints [i*2 + 1]);
else
mapped = ::basegfx::B2DPoint (pPoints [i*2], pPoints [i*2 + 1]);
if (pPointTypes) {
if ((pPointTypes [i] & 0x07) == 3) {
if (((i - last_normal )% 3) == 1) {
polygon.setNextControlPoint (p - 1, mapped);
SAL_INFO ("cppcanvas.emf", "polygon append next: " << p - 1 << " mapped: " << mapped.getX () << "," << mapped.getY ());
continue;
} else if (((i - last_normal) % 3) == 2) {
prev = mapped;
hasPrev = true;
continue;
}
} else
last_normal = i;
}
polygon.append (mapped);
SAL_INFO ("cppcanvas.emf", "polygon append point: " << pPoints [i*2] << "," << pPoints [i*2 + 1] << " mapped: " << mapped.getX () << ":" << mapped.getY ());
if (hasPrev) {
polygon.setPrevControlPoint (p, prev);
SAL_INFO ("cppcanvas.emf", "polygon append prev: " << p << " mapped: " << prev.getX () << "," << prev.getY ());
hasPrev = false;
}
p ++;
if (pPointTypes && (pPointTypes [i] & 0x80)) { // closed polygon
polygon.setClosed (true);
aPolygon.append (polygon);
SAL_INFO ("cppcanvas.emf", "close polygon");
last_normal = i + 1;
p = 0;
polygon.clear ();
}
}
// Draw an extra line between the last point and the first point, to close the shape.
if (bAddLineToCloseShape) {
if (bMapIt)
polygon.append (rR.Map (pPoints [0], pPoints [1]) );
else
polygon.append (::basegfx::B2DPoint (pPoints [0], pPoints [1]) );
}
if (polygon.count ()) {
aPolygon.append (polygon);
#if OSL_DEBUG_LEVEL > 1
for (unsigned int i=0; i<aPolygon.count(); i++) {
polygon = aPolygon.getB2DPolygon(i);
SAL_INFO ("cppcanvas.emf", "polygon: " << i);
for (unsigned int j=0; j<polygon.count(); j++) {
::basegfx::B2DPoint point = polygon.getB2DPoint(j);
SAL_INFO ("cppcanvas.emf", "point: " << point.getX() << "," << point.getY());
if (polygon.isPrevControlPointUsed(j)) {
point = polygon.getPrevControlPoint(j);
SAL_INFO ("cppcanvas.emf", "prev: " << point.getX() << "," << point.getY());
}
if (polygon.isNextControlPointUsed(j)) {
point = polygon.getNextControlPoint(j);
SAL_INFO ("cppcanvas.emf", "next: " << point.getX() << "," << point.getY());
}
}
}
#endif
}
return aPolygon;
}
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */