LibreOffice Module vcl (master) 1
line.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
24#include <tools/debug.hxx>
26
27#include <vcl/lineinfo.hxx>
28#include <vcl/metaact.hxx>
29#include <vcl/virdev.hxx>
30
31#include <drawmode.hxx>
32#include <salgdi.hxx>
33
34#include <cassert>
35#include <numeric>
36
38{
39
40 if ( mpMetaFile )
42
43 if ( mbLineColor )
44 {
45 mbInitLineColor = true;
46 mbLineColor = false;
48 }
49
50 if( mpAlphaVDev )
52}
53
54void OutputDevice::SetLineColor( const Color& rColor )
55{
56
57 Color aColor = vcl::drawmode::GetLineColor(rColor, GetDrawMode(), GetSettings().GetStyleSettings());
58
59 if( mpMetaFile )
60 mpMetaFile->AddAction( new MetaLineColorAction( aColor, true ) );
61
62 if( aColor.IsTransparent() )
63 {
64 if ( mbLineColor )
65 {
66 mbInitLineColor = true;
67 mbLineColor = false;
69 }
70 }
71 else
72 {
73 if( maLineColor != aColor )
74 {
75 mbInitLineColor = true;
76 mbLineColor = true;
77 maLineColor = aColor;
78 }
79 }
80
81 if( mpAlphaVDev )
83}
84
86{
88
89 if( mbLineColor )
90 {
93 else if( RasterOp::N1 == meRasterOp )
95 else if( RasterOp::Invert == meRasterOp )
97 else
99 }
100 else
101 {
103 }
104
105 mbInitLineColor = false;
106}
107
108void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt,
109 const LineInfo& rLineInfo )
110{
111 assert(!is_double_buffered_window());
112
113 if ( rLineInfo.IsDefault() )
114 {
115 DrawLine( rStartPt, rEndPt );
116 return;
117 }
118
119 if ( mpMetaFile )
120 mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt, rLineInfo ) );
121
122 if ( !IsDeviceOutputNecessary() || !mbLineColor || ( LineStyle::NONE == rLineInfo.GetStyle() ) || ImplIsRecordLayout() )
123 return;
124
125 if( !mpGraphics && !AcquireGraphics() )
126 return;
127 assert(mpGraphics);
128
129 if ( mbInitClipRegion )
131
132 if ( mbOutputClipped )
133 return;
134
135 const Point aStartPt( ImplLogicToDevicePixel( rStartPt ) );
136 const Point aEndPt( ImplLogicToDevicePixel( rEndPt ) );
137 const LineInfo aInfo( ImplLogicToDevicePixel( rLineInfo ) );
138 const bool bDashUsed(LineStyle::Dash == aInfo.GetStyle());
139 const bool bLineWidthUsed(aInfo.GetWidth() > 1);
140
141 if ( mbInitLineColor )
143
144 if(bDashUsed || bLineWidthUsed)
145 {
146 basegfx::B2DPolygon aLinePolygon;
147 aLinePolygon.append(basegfx::B2DPoint(aStartPt.X(), aStartPt.Y()));
148 aLinePolygon.append(basegfx::B2DPoint(aEndPt.X(), aEndPt.Y()));
149
150 drawLine( basegfx::B2DPolyPolygon(aLinePolygon), aInfo );
151 }
152 else
153 {
154 mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y(), *this );
155 }
156
157 if( mpAlphaVDev )
158 mpAlphaVDev->DrawLine( rStartPt, rEndPt, rLineInfo );
159}
160
161void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt )
162{
163 assert(!is_double_buffered_window());
164
165 if ( mpMetaFile )
166 mpMetaFile->AddAction( new MetaLineAction( rStartPt, rEndPt ) );
167
169 return;
170
171 if ( !mpGraphics && !AcquireGraphics() )
172 return;
173 assert(mpGraphics);
174
175 if ( mbInitClipRegion )
177
178 if ( mbOutputClipped )
179 return;
180
181 if ( mbInitLineColor )
183
184 bool bDrawn = false;
185
186 // #i101598# support AA and snap for lines, too
189 && IsLineColor())
190 {
191 // at least transform with double precision to device coordinates; this will
192 // avoid pixel snap of single, appended lines
194 basegfx::B2DPolygon aB2DPolyLine;
195
196 aB2DPolyLine.append(basegfx::B2DPoint(rStartPt.X(), rStartPt.Y()));
197 aB2DPolyLine.append(basegfx::B2DPoint(rEndPt.X(), rEndPt.Y()));
198 aB2DPolyLine.transform( aTransform );
199
200 const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
201
202 bDrawn = mpGraphics->DrawPolyLine(
204 aB2DPolyLine,
205 0.0,
206 0.0, // tdf#124848 hairline
207 nullptr, // MM01
209 css::drawing::LineCap_BUTT,
210 basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
211 bPixelSnapHairline,
212 *this);
213 }
214 if(!bDrawn)
215 {
216 const Point aStartPt(ImplLogicToDevicePixel(rStartPt));
217 const Point aEndPt(ImplLogicToDevicePixel(rEndPt));
218 mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y(), *this );
219 }
220
221 if( mpAlphaVDev )
222 mpAlphaVDev->DrawLine( rStartPt, rEndPt );
223}
224
225void OutputDevice::drawLine( basegfx::B2DPolyPolygon aLinePolyPolygon, const LineInfo& rInfo )
226{
229 && IsLineColor());
230 basegfx::B2DPolyPolygon aFillPolyPolygon;
231 const bool bDashUsed(LineStyle::Dash == rInfo.GetStyle());
232 const bool bLineWidthUsed(rInfo.GetWidth() > 1);
233
234 if(bDashUsed && aLinePolyPolygon.count())
235 {
236 ::std::vector< double > fDotDashArray = rInfo.GetDotDashArray();
237 const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0));
238
239 if(fAccumulated > 0.0)
240 {
242
243 for(auto const& rPolygon : std::as_const(aLinePolyPolygon))
244 {
245 basegfx::B2DPolyPolygon aLineTarget;
247 rPolygon,
248 fDotDashArray,
249 &aLineTarget);
250 aResult.append(aLineTarget);
251 }
252
253 aLinePolyPolygon = aResult;
254 }
255 }
256
257 if(bLineWidthUsed && aLinePolyPolygon.count())
258 {
259 const double fHalfLineWidth((rInfo.GetWidth() * 0.5) + 0.5);
260
261 if(aLinePolyPolygon.areControlPointsUsed())
262 {
263 // #i110768# When area geometry has to be created, do not
264 // use the fallback bezier decomposition inside createAreaGeometry,
265 // but one that is at least as good as ImplSubdivideBezier was.
266 // There, Polygon::AdaptiveSubdivide was used with default parameter
267 // 1.0 as quality index.
268 static int nRecurseLimit = utl::ConfigManager::IsFuzzing() ? 10 : 30;
269 aLinePolyPolygon = basegfx::utils::adaptiveSubdivideByDistance(aLinePolyPolygon, 1.0, nRecurseLimit);
270 }
271
272 for(auto const& rPolygon : std::as_const(aLinePolyPolygon))
273 {
275 rPolygon,
276 fHalfLineWidth,
277 rInfo.GetLineJoin(),
278 rInfo.GetLineCap()));
279 }
280
281 aLinePolyPolygon.clear();
282 }
283
284 GDIMetaFile* pOldMetaFile = mpMetaFile;
285 mpMetaFile = nullptr;
286
287 if(aLinePolyPolygon.count())
288 {
289 for(auto const& rB2DPolygon : std::as_const(aLinePolyPolygon))
290 {
291 const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
292 bool bDone(false);
293
294 if(bTryB2d)
295 {
296 bDone = mpGraphics->DrawPolyLine(
298 rB2DPolygon,
299 0.0,
300 0.0, // tdf#124848 hairline
301 nullptr, // MM01
303 css::drawing::LineCap_BUTT,
304 basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
305 bPixelSnapHairline,
306 *this);
307 }
308
309 if(!bDone)
310 {
311 tools::Polygon aPolygon(rB2DPolygon);
313 aPolygon.GetSize(),
314 aPolygon.GetPointAry(),
315 *this);
316 }
317 }
318 }
319
320 if(aFillPolyPolygon.count())
321 {
322 const Color aOldLineColor( maLineColor );
323 const Color aOldFillColor( maFillColor );
324
325 SetLineColor();
327 SetFillColor( aOldLineColor );
329
330 bool bDone(false);
331
332 if(bTryB2d)
333 {
336 aFillPolyPolygon,
337 0.0,
338 *this);
339 }
340
341 if(!bDone)
342 {
343 for(auto const& rB2DPolygon : std::as_const(aFillPolyPolygon))
344 {
345 tools::Polygon aPolygon(rB2DPolygon);
346
347 // need to subdivide, mpGraphics->DrawPolygon ignores curves
348 aPolygon.AdaptiveSubdivide(aPolygon);
349 mpGraphics->DrawPolygon(aPolygon.GetSize(), aPolygon.GetConstPointAry(), *this);
350 }
351 }
352
353 SetFillColor( aOldFillColor );
354 SetLineColor( aOldLineColor );
355 }
356
357 mpMetaFile = pOldMetaFile;
358}
359
360/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsTransparent() const
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:581
virtual void InitClipRegion()
SAL_DLLPRIVATE bool is_double_buffered_window() const
SAL_DLLPRIVATE void InitLineColor()
Definition: line.cxx:85
bool mbOutputClipped
Definition: outdev.hxx:246
RasterOp GetRasterOp() const
Definition: outdev.hxx:497
SAL_DLLPRIVATE tools::Rectangle ImplLogicToDevicePixel(const tools::Rectangle &rLogicRect) const
Convert a logical rectangle to a rectangle in physical device pixel units.
Definition: map.cxx:391
virtual bool AcquireGraphics() const =0
Acquire a graphics device that the output device uses to draw on.
SAL_DLLPRIVATE bool ImplIsRecordLayout() const
Definition: outdev.cxx:709
void DrawLine(const Point &rStartPt, const Point &rEndPt)
Definition: line.cxx:161
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:186
SAL_DLLPRIVATE void InitFillColor()
Definition: fill.cxx:76
SAL_DLLPRIVATE void drawLine(basegfx::B2DPolyPolygon aLinePolyPolygon, const LineInfo &rInfo)
Helper for line geometry paint with support for graphic expansion (pattern and fat_to_area)
Definition: line.cxx:225
void SetLineColor()
Definition: line.cxx:37
bool mbInitLineColor
Definition: outdev.hxx:249
SalGraphics * mpGraphics
Graphics context to draw on.
Definition: outdev.hxx:183
bool IsLineColor() const
Definition: outdev.hxx:512
bool mbInitClipRegion
Definition: outdev.hxx:253
RasterOp meRasterOp
Definition: outdev.hxx:233
void SetFillColor()
Definition: fill.cxx:29
AntialiasingFlags mnAntialiasing
Definition: outdev.hxx:238
bool IsDeviceOutputNecessary() const
Definition: outdev.hxx:482
VclPtr< VirtualDevice > mpAlphaVDev
Definition: outdev.hxx:197
SAL_DLLPRIVATE basegfx::B2DHomMatrix ImplGetDeviceTransformation() const
Get device transformation.
Definition: map.cxx:929
Color maLineColor
Definition: outdev.hxx:227
DrawModeFlags GetDrawMode() const
Definition: outdev.hxx:488
Color maFillColor
Definition: outdev.hxx:228
const AllSettings & GetSettings() const
Definition: outdev.hxx:289
bool mbLineColor
Definition: outdev.hxx:247
virtual void SetROPLineColor(SalROPColor nROPColor)=0
virtual void SetLineColor()=0
void DrawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2, const OutputDevice &rOutDev)
virtual bool supportsOperation(OutDevSupportType) const =0
void DrawPolyLine(sal_uInt32 nPoints, Point const *pPtAry, const OutputDevice &rOutDev)
void DrawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32 *pPoints, const Point **pPtAry, const OutputDevice &rOutDev)
void DrawPolygon(sal_uInt32 nPoints, const Point *pPtAry, const OutputDevice &rOutDev)
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
bool areControlPointsUsed() const
sal_uInt32 count() const
void transform(const basegfx::B2DHomMatrix &rMatrix)
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
const Point * GetConstPointAry() const
sal_uInt16 GetSize() const
Point * GetPointAry()
void AdaptiveSubdivide(tools::Polygon &rResult, const double d=1.0) const
static bool IsFuzzing()
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
constexpr ::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
#define DBG_TESTSOLARMUTEX()
B2DPolygon adaptiveSubdivideByDistance(const B2DPolygon &rCandidate, double fDistanceBound, int nRecurseLimit)
void applyLineDashing(const B2DPolygon &rCandidate, const std::vector< double > &rDotDashArray, B2DPolyPolygon *pLineTarget, B2DPolyPolygon *pGapTarget, double fDotDashLength)
B2DPolyPolygon createAreaGeometry(const B2DPolygon &rCandidate, double fHalfLineWidth, B2DLineJoin eJoin, css::drawing::LineCap eCap, double fMaxAllowedAngle=basegfx::deg2rad(12.5), double fMaxPartOfEdge=0.4, double fMiterMinimumAngle=basegfx::deg2rad(15.0), basegfx::triangulator::B2DTriangleVector *pTriangles=nullptr)
constexpr double deg2rad(double v)
Color GetLineColor(Color const &rColor, DrawModeFlags nDrawMode, StyleSettings const &rStyleSettings)
Definition: drawmode.cxx:30