174994d13SStephan Aßmus/*
292772bbdSStephan Aßmus * Copyright 2009, Christian Packmann.
3fa6a00c6SStephan Aßmus * Copyright 2008, Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>.
4b74fecd7SStephan Aßmus * Copyright 2005-2014, Stephan A��mus <superstippi@gmx.de>.
5d56beda4SJulian Harnath * Copyright 2015, Julian Harnath <julian.harnath@rwth-aachen.de>
6fa6a00c6SStephan Aßmus * All rights reserved. Distributed under the terms of the MIT License.
774994d13SStephan Aßmus */
84569b90dSStephan Aßmus
911444759SAxel Dörfler
10c97f4931SAxel Dörfler/*!	API to the Anti-Grain Geometry based "Painter" drawing backend. Manages
11c97f4931SAxel Dörfler	rendering pipe-lines for stroke, fills, bitmap and text rendering.
12c97f4931SAxel Dörfler*/
13c97f4931SAxel Dörfler
1411444759SAxel Dörfler
15c97f4931SAxel Dörfler#include "Painter.h"
1692772bbdSStephan Aßmus
1796c78002SStephan Aßmus#include <new>
18c97f4931SAxel Dörfler
194569b90dSStephan Aßmus#include <stdio.h>
20597841daSStephan Aßmus#include <string.h>
2146b39e83SStephan Aßmus#include <syslog.h>
224569b90dSStephan Aßmus
234569b90dSStephan Aßmus#include <Bitmap.h>
24a356096dSStephan Aßmus#include <GraphicsDefs.h>
254569b90dSStephan Aßmus#include <Region.h>
260118ad76SStephan Aßmus#include <String.h>
27991547efSStephan Aßmus#include <GradientLinear.h>
28991547efSStephan Aßmus#include <GradientRadial.h>
29991547efSStephan Aßmus#include <GradientRadialFocus.h>
30991547efSStephan Aßmus#include <GradientDiamond.h>
31991547efSStephan Aßmus#include <GradientConic.h>
324569b90dSStephan Aßmus
332f9eca85SStefano Ceccherini#include <ShapePrivate.h>
342f9eca85SStefano Ceccherini
354569b90dSStephan Aßmus#include <agg_bezier_arc.h>
36a356096dSStephan Aßmus#include <agg_bounding_rect.h>
370118ad76SStephan Aßmus#include <agg_conv_clip_polygon.h>
384569b90dSStephan Aßmus#include <agg_conv_curve.h>
394569b90dSStephan Aßmus#include <agg_conv_stroke.h>
404569b90dSStephan Aßmus#include <agg_ellipse.h>
41e39da397SStephan Aßmus#include <agg_image_accessors.h>
424569b90dSStephan Aßmus#include <agg_path_storage.h>
43e39da397SStephan Aßmus#include <agg_pixfmt_rgba.h>
444569b90dSStephan Aßmus#include <agg_rounded_rect.h>
45e39da397SStephan Aßmus#include <agg_span_allocator.h>
46e39da397SStephan Aßmus#include <agg_span_image_filter_rgba.h>
474569b90dSStephan Aßmus#include <agg_span_interpolator_linear.h>
484569b90dSStephan Aßmus
49dd98ed8dSStephan Aßmus#include "drawing_support.h"
50f5b6cf65SStephan Aßmus
51aca4f50dSAxel Dörfler#include "DrawState.h"
52517e54d0SStephan Aßmus
5396c78002SStephan Aßmus#include <AutoDeleter.h>
54162a7f5fSStephan Aßmus#include <View.h>
55162a7f5fSStephan Aßmus
56f08d5477SAdrien Destugues#include "AlphaMask.h"
57e353fe39SJulian Harnath#include "BitmapPainter.h"
58597841daSStephan Aßmus#include "DrawingMode.h"
5959e13a3fSStephan Aßmus#include "GlobalSubpixelSettings.h"
604569b90dSStephan Aßmus#include "PatternHandler.h"
614569b90dSStephan Aßmus#include "RenderingBuffer.h"
62a0c67cdbSStephan Aßmus#include "ServerBitmap.h"
63a0c67cdbSStephan Aßmus#include "ServerFont.h"
642de437faSStephan Aßmus#include "SystemPalette.h"
654569b90dSStephan Aßmus
6692772bbdSStephan Aßmus#include "AppServer.h"
6792772bbdSStephan Aßmus
6896c78002SStephan Aßmususing std::nothrow;
69ac167e6eSStephan Aßmus
7096c78002SStephan Aßmus#undef TRACE
71991547efSStephan Aßmus// #define TRACE_PAINTER
72fc8e77f8SStephan Aßmus#ifdef TRACE_PAINTER
73fc8e77f8SStephan Aßmus#	define TRACE(x...)		printf(x)
74fc8e77f8SStephan Aßmus#else
75fc8e77f8SStephan Aßmus#	define TRACE(x...)
76fc8e77f8SStephan Aßmus#endif
77fc8e77f8SStephan Aßmus
78991547efSStephan Aßmus//#define TRACE_GRADIENTS
79991547efSStephan Aßmus#ifdef TRACE_GRADIENTS
80991547efSStephan Aßmus#	include <OS.h>
81991547efSStephan Aßmus#	define GTRACE(x...)		debug_printf(x)
82991547efSStephan Aßmus#else
83991547efSStephan Aßmus#	define GTRACE(x...)
84991547efSStephan Aßmus#endif
85991547efSStephan Aßmus
86991547efSStephan Aßmus
8792acca78SStephan Aßmus#define CHECK_CLIPPING	if (!fValidClipping) return BRect(0, 0, -1, -1);
8838287e02SStephan Aßmus#define CHECK_CLIPPING_NO_RETURN	if (!fValidClipping) return;
89924b7ab2SStephan Aßmus
90b6284c7fSAxel Dörfler
91e353fe39SJulian Harnath// Shortcuts for accessing internal data
92e353fe39SJulian Harnath#define fBuffer					fInternal.fBuffer
93e353fe39SJulian Harnath#define fPixelFormat			fInternal.fPixelFormat
94e353fe39SJulian Harnath#define fBaseRenderer			fInternal.fBaseRenderer
95e353fe39SJulian Harnath#define fUnpackedScanline		fInternal.fUnpackedScanline
96e353fe39SJulian Harnath#define fPackedScanline			fInternal.fPackedScanline
97e353fe39SJulian Harnath#define fRasterizer				fInternal.fRasterizer
98e353fe39SJulian Harnath#define fRenderer				fInternal.fRenderer
99e353fe39SJulian Harnath#define fRendererBin			fInternal.fRendererBin
100e353fe39SJulian Harnath#define fSubpixPackedScanline	fInternal.fSubpixPackedScanline
101e353fe39SJulian Harnath#define fSubpixUnpackedScanline	fInternal.fSubpixUnpackedScanline
102e353fe39SJulian Harnath#define fSubpixRasterizer		fInternal.fSubpixRasterizer
103e353fe39SJulian Harnath#define fSubpixRenderer			fInternal.fSubpixRenderer
104e353fe39SJulian Harnath#define fMaskedUnpackedScanline	fInternal.fMaskedUnpackedScanline
105f4f05935SJulian Harnath#define fClippedAlphaMask		fInternal.fClippedAlphaMask
106e353fe39SJulian Harnath#define fPath					fInternal.fPath
107e353fe39SJulian Harnath#define fCurve					fInternal.fCurve
108e353fe39SJulian Harnath
109b6284c7fSAxel Dörfler
110b6284c7fSAxel Dörflerstatic uint32 detect_simd();
111b6284c7fSAxel Dörfler
112e353fe39SJulian Harnathuint32 gSIMDFlags = detect_simd();
113b6284c7fSAxel Dörfler
114b6284c7fSAxel Dörfler
115b6284c7fSAxel Dörfler/*!	Detect SIMD flags for use in AppServer. Checks all CPUs in the system
116b6284c7fSAxel Dörfler	and chooses the minimum supported set of instructions.
117b6284c7fSAxel Dörfler*/
118b6284c7fSAxel Dörflerstatic uint32
119b6284c7fSAxel Dörflerdetect_simd()
120b6284c7fSAxel Dörfler{
1215ffbe7d7SAugustin Cavalier#if __i386__
122b6284c7fSAxel Dörfler	// Only scan CPUs for which we are certain the SIMD flags are properly
123b6284c7fSAxel Dörfler	// defined.
124b6284c7fSAxel Dörfler	const char* vendorNames[] = {
125b6284c7fSAxel Dörfler		"GenuineIntel",
126b6284c7fSAxel Dörfler		"AuthenticAMD",
127b6284c7fSAxel Dörfler		"CentaurHauls", // Via CPUs, MMX and SSE support
128b6284c7fSAxel Dörfler		"RiseRiseRise", // should be MMX-only
129b6284c7fSAxel Dörfler		"CyrixInstead", // MMX-only, but custom MMX extensions
130b6284c7fSAxel Dörfler		"GenuineTMx86", // MMX and SSE
131b6284c7fSAxel Dörfler		0
132b6284c7fSAxel Dörfler	};
133b6284c7fSAxel Dörfler
134b6284c7fSAxel Dörfler	system_info systemInfo;
135b6284c7fSAxel Dörfler	if (get_system_info(&systemInfo) != B_OK)
136b6284c7fSAxel Dörfler		return 0;
137b6284c7fSAxel Dörfler
138b6284c7fSAxel Dörfler	// We start out with all flags set and end up with only those flags
139b6284c7fSAxel Dörfler	// supported across all CPUs found.
140b6284c7fSAxel Dörfler	uint32 systemSIMD = 0xffffffff;
141b6284c7fSAxel Dörfler
1421bc7045fSPawel Dziepak	for (uint32 cpu = 0; cpu < systemInfo.cpu_count; cpu++) {
143b6284c7fSAxel Dörfler		cpuid_info cpuInfo;
144b6284c7fSAxel Dörfler		get_cpuid(&cpuInfo, 0, cpu);
145b6284c7fSAxel Dörfler
146b6284c7fSAxel Dörfler		// Get the vendor string and terminate it manually
147b6284c7fSAxel Dörfler		char vendor[13];
148b6284c7fSAxel Dörfler		memcpy(vendor, cpuInfo.eax_0.vendor_id, 12);
149b6284c7fSAxel Dörfler		vendor[12] = 0;
150b6284c7fSAxel Dörfler
151b6284c7fSAxel Dörfler		bool vendorFound = false;
152b6284c7fSAxel Dörfler		for (uint32 i = 0; vendorNames[i] != 0; i++) {
153b6284c7fSAxel Dörfler			if (strcmp(vendor, vendorNames[i]) == 0)
154b6284c7fSAxel Dörfler				vendorFound = true;
155b6284c7fSAxel Dörfler		}
156b6284c7fSAxel Dörfler
157b6284c7fSAxel Dörfler		uint32 cpuSIMD = 0;
158b6284c7fSAxel Dörfler		uint32 maxStdFunc = cpuInfo.regs.eax;
159b6284c7fSAxel Dörfler		if (vendorFound && maxStdFunc >= 1) {
160b6284c7fSAxel Dörfler			get_cpuid(&cpuInfo, 1, 0);
161b6284c7fSAxel Dörfler			uint32 edx = cpuInfo.regs.edx;
162b6284c7fSAxel Dörfler			if (edx & (1 << 23))
163b6284c7fSAxel Dörfler				cpuSIMD |= APPSERVER_SIMD_MMX;
164b6284c7fSAxel Dörfler			if (edx & (1 << 25))
165b6284c7fSAxel Dörfler				cpuSIMD |= APPSERVER_SIMD_SSE;
166b6284c7fSAxel Dörfler		} else {
167b6284c7fSAxel Dörfler			// no flags can be identified
168b6284c7fSAxel Dörfler			cpuSIMD = 0;
169b6284c7fSAxel Dörfler		}
170b6284c7fSAxel Dörfler		systemSIMD &= cpuSIMD;
171b6284c7fSAxel Dörfler	}
172b6284c7fSAxel Dörfler	return systemSIMD;
1735ffbe7d7SAugustin Cavalier#else	// !__i386__
17411444759SAxel Dörfler	return 0;
17511444759SAxel Dörfler#endif
176b6284c7fSAxel Dörfler}
177b6284c7fSAxel Dörfler
178b6284c7fSAxel Dörfler
179b6284c7fSAxel Dörfler// #pragma mark -
180b6284c7fSAxel Dörfler
1817f5bbbdcSAxel Dörfler
1824569b90dSStephan AßmusPainter::Painter()
18392772bbdSStephan Aßmus	:
184e353fe39SJulian Harnath	fInternal(fPatternHandler),
18592772bbdSStephan Aßmus	fSubpixelPrecise(false),
18692772bbdSStephan Aßmus	fValidClipping(false),
18792772bbdSStephan Aßmus	fDrawingText(false),
18892772bbdSStephan Aßmus	fAttached(false),
18992772bbdSStephan Aßmus
19092772bbdSStephan Aßmus	fPenSize(1.0),
19192772bbdSStephan Aßmus	fClippingRegion(NULL),
19292772bbdSStephan Aßmus	fDrawingMode(B_OP_COPY),
19392772bbdSStephan Aßmus	fAlphaSrcMode(B_PIXEL_ALPHA),
19492772bbdSStephan Aßmus	fAlphaFncMode(B_ALPHA_OVERLAY),
19592772bbdSStephan Aßmus	fLineCapMode(B_BUTT_CAP),
19692772bbdSStephan Aßmus	fLineJoinMode(B_MITER_JOIN),
19792772bbdSStephan Aßmus	fMiterLimit(B_DEFAULT_MITER_LIMIT),
19892772bbdSStephan Aßmus
19992772bbdSStephan Aßmus	fPatternHandler(),
20092772bbdSStephan Aßmus	fTextRenderer(fSubpixRenderer, fRenderer, fRendererBin, fUnpackedScanline,
201b4671bebSStephan Aßmus		fSubpixUnpackedScanline, fSubpixRasterizer, fMaskedUnpackedScanline,
202b4671bebSStephan Aßmus		fTransform)
2034569b90dSStephan Aßmus{
20492772bbdSStephan Aßmus	fPixelFormat.SetDrawingMode(fDrawingMode, fAlphaSrcMode, fAlphaFncMode,
20592772bbdSStephan Aßmus		false);
206eb9f93f3SStephan Aßmus
207eb9f93f3SStephan Aßmus#if ALIASED_DRAWING
208eb9f93f3SStephan Aßmus	fRasterizer.gamma(agg::gamma_threshold(0.5));
20959e13a3fSStephan Aßmus	fSubpixRasterizer.gamma(agg:gamma_threshold(0.5));
210208e6678SStephan Aßmus#endif
2114569b90dSStephan Aßmus}
2124569b90dSStephan Aßmus
213c97f4931SAxel Dörfler
2144569b90dSStephan Aßmus// destructor
2154569b90dSStephan AßmusPainter::~Painter()
2164569b90dSStephan Aßmus{
2174569b90dSStephan Aßmus}
2184569b90dSStephan Aßmus
219c97f4931SAxel Dörfler
2204569b90dSStephan Aßmus// #pragma mark -
2214569b90dSStephan Aßmus
222c97f4931SAxel Dörfler
2234569b90dSStephan Aßmus// AttachToBuffer
2244569b90dSStephan Aßmusvoid
2254569b90dSStephan AßmusPainter::AttachToBuffer(RenderingBuffer* buffer)
2264569b90dSStephan Aßmus{
22792772bbdSStephan Aßmus	if (buffer && buffer->InitCheck() >= B_OK
22892772bbdSStephan Aßmus		&& (buffer->ColorSpace() == B_RGBA32
22992772bbdSStephan Aßmus			|| buffer->ColorSpace() == B_RGB32)) {
23042a2db36SStephan Aßmus		// TODO: implement drawing on B_RGB24, B_RGB15, B_RGB16,
23142a2db36SStephan Aßmus		// B_CMAP8 and B_GRAY8 :-[
23242a2db36SStephan Aßmus		// (if ever we want to support some devices where this gives
23342a2db36SStephan Aßmus		// a great speed up, right now it seems fine, even in emulation)
23442a2db36SStephan Aßmus
235eb9f93f3SStephan Aßmus		fBuffer.attach((uint8*)buffer->Bits(),
236eb9f93f3SStephan Aßmus			buffer->Width(), buffer->Height(), buffer->BytesPerRow());
2374569b90dSStephan Aßmus
23842a2db36SStephan Aßmus		fAttached = true;
23987911f6cSStephan Aßmus		fValidClipping = fClippingRegion != NULL
24042a2db36SStephan Aßmus			&& fClippingRegion->Frame().IsValid();
2414569b90dSStephan Aßmus
2424569b90dSStephan Aßmus		// These are the AGG renderes and rasterizes which
2434569b90dSStephan Aßmus		// will be used for stroking paths
2444569b90dSStephan Aßmus
245f7e1df75SStephan Aßmus		_SetRendererColor(fPatternHandler.HighColor());
2464569b90dSStephan Aßmus	}
2474569b90dSStephan Aßmus}
2484569b90dSStephan Aßmus
249c97f4931SAxel Dörfler
2504569b90dSStephan Aßmus// DetachFromBuffer
2514569b90dSStephan Aßmusvoid
2524569b90dSStephan AßmusPainter::DetachFromBuffer()
2534569b90dSStephan Aßmus{
25442a2db36SStephan Aßmus	fBuffer.attach(NULL, 0, 0, 0);
25542a2db36SStephan Aßmus	fAttached = false;
25642a2db36SStephan Aßmus	fValidClipping = false;
2574569b90dSStephan Aßmus}
2584569b90dSStephan Aßmus
259c97f4931SAxel Dörfler
260ff852457SStephan Aßmus// Bounds
261ff852457SStephan AßmusBRect
262ff852457SStephan AßmusPainter::Bounds() const
263ff852457SStephan Aßmus{
264ff852457SStephan Aßmus	return BRect(0, 0, fBuffer.width() - 1, fBuffer.height() - 1);
265ff852457SStephan Aßmus}
266ff852457SStephan Aßmus
267c97f4931SAxel Dörfler
268208e6678SStephan Aßmus// #pragma mark -
269208e6678SStephan Aßmus
270c97f4931SAxel Dörfler
271aca4f50dSAxel Dörfler// SetDrawState
272517e54d0SStephan Aßmusvoid
27363a30a47SStephan AßmusPainter::SetDrawState(const DrawState* state, int32 xOffset, int32 yOffset)
274517e54d0SStephan Aßmus{
27563a30a47SStephan Aßmus	// NOTE: The custom clipping in "state" is ignored, because it has already
276c9d2046fSStephan Aßmus	// been taken into account elsewhere
277359c905cSStephan Aßmus
2780634c42fSStephan Aßmus	// NOTE: Usually this function is only used when the "current view"
2790634c42fSStephan Aßmus	// is switched in the ServerWindow and after the decorator has drawn
2800634c42fSStephan Aßmus	// and messed up the state. For other graphics state changes, the
2810634c42fSStephan Aßmus	// Painter methods are used directly, so this function is much less
2820634c42fSStephan Aßmus	// speed critical than it used to be.
2839b417f64SJulian Harnath
28463a30a47SStephan Aßmus	SetTransform(state->CombinedTransform(), xOffset, yOffset);
2850634c42fSStephan Aßmus
28663a30a47SStephan Aßmus	SetPenSize(state->PenSize());
2871f0a4ee8SStephan Aßmus
28863a30a47SStephan Aßmus	SetFont(state);
289359c905cSStephan Aßmus
29063a30a47SStephan Aßmus	fSubpixelPrecise = state->SubPixelPrecise();
291359c905cSStephan Aßmus
292f4f05935SJulian Harnath	if (state->GetAlphaMask() != NULL) {
2939b417f64SJulian Harnath		fMaskedUnpackedScanline = state->GetAlphaMask()->Scanline();
294f4f05935SJulian Harnath		fClippedAlphaMask = state->GetAlphaMask()->Mask();
295f4f05935SJulian Harnath	} else {
296215119a1SStephan Aßmus		fMaskedUnpackedScanline = NULL;
297f4f05935SJulian Harnath		fClippedAlphaMask = NULL;
298f4f05935SJulian Harnath	}
299215119a1SStephan Aßmus
3004da1508aSStephan Aßmus	// any of these conditions means we need to use a different drawing
3014da1508aSStephan Aßmus	// mode instance
3020634c42fSStephan Aßmus	bool updateDrawingMode
30363a30a47SStephan Aßmus		= !(state->GetPattern() == fPatternHandler.GetPattern())
30463a30a47SStephan Aßmus			|| state->GetDrawingMode() != fDrawingMode
30563a30a47SStephan Aßmus			|| (state->GetDrawingMode() == B_OP_ALPHA
30663a30a47SStephan Aßmus				&& (state->AlphaSrcMode() != fAlphaSrcMode
30763a30a47SStephan Aßmus					|| state->AlphaFncMode() != fAlphaFncMode));
30863a30a47SStephan Aßmus
30963a30a47SStephan Aßmus	fDrawingMode = state->GetDrawingMode();
31063a30a47SStephan Aßmus	fAlphaSrcMode = state->AlphaSrcMode();
31163a30a47SStephan Aßmus	fAlphaFncMode = state->AlphaFncMode();
31263a30a47SStephan Aßmus	fPatternHandler.SetPattern(state->GetPattern());
313eb9f93f3SStephan Aßmus	fPatternHandler.SetOffsets(xOffset, yOffset);
31463a30a47SStephan Aßmus	fLineCapMode = state->LineCapMode();
31563a30a47SStephan Aßmus	fLineJoinMode = state->LineJoinMode();
31663a30a47SStephan Aßmus	fMiterLimit = state->MiterLimit();
3174da1508aSStephan Aßmus
318b74fecd7SStephan Aßmus	SetFillRule(state->FillRule());
319b74fecd7SStephan Aßmus
320dd98ed8dSStephan Aßmus	// adopt the color *after* the pattern is set
321dd98ed8dSStephan Aßmus	// to set the renderers to the correct color
32263a30a47SStephan Aßmus	SetHighColor(state->HighColor());
32363a30a47SStephan Aßmus	SetLowColor(state->LowColor());
324208e6678SStephan Aßmus
32557e24888SStephan Aßmus	if (updateDrawingMode)
326208e6678SStephan Aßmus		_UpdateDrawingMode();
327517e54d0SStephan Aßmus}
328517e54d0SStephan Aßmus
329c97f4931SAxel Dörfler
330208e6678SStephan Aßmus// #pragma mark - state
3314569b90dSStephan Aßmus
332c97f4931SAxel Dörfler
3334569b90dSStephan Aßmus// ConstrainClipping
3344569b90dSStephan Aßmusvoid
33565abd9dfSStephan AßmusPainter::ConstrainClipping(const BRegion* region)
3364569b90dSStephan Aßmus{
3372cfe93e7SStephan Aßmus	fClippingRegion = region;
338eb9f93f3SStephan Aßmus	fBaseRenderer.set_clipping_region(const_cast<BRegion*>(region));
33942a2db36SStephan Aßmus	fValidClipping = region->Frame().IsValid() && fAttached;
3404423855cSStephan Aßmus
3414423855cSStephan Aßmus	if (fValidClipping) {
3424423855cSStephan Aßmus		clipping_rect cb = fClippingRegion->FrameInt();
343eb9f93f3SStephan Aßmus		fRasterizer.clip_box(cb.left, cb.top, cb.right + 1, cb.bottom + 1);
34459e13a3fSStephan Aßmus		fSubpixRasterizer.clip_box(cb.left, cb.top, cb.right + 1, cb.bottom + 1);
3454423855cSStephan Aßmus	}
3464569b90dSStephan Aßmus}
3474569b90dSStephan Aßmus
348c97f4931SAxel Dörfler
34963a30a47SStephan Aßmusvoid
35063a30a47SStephan AßmusPainter::SetTransform(BAffineTransform transform, int32 xOffset, int32 yOffset)
35163a30a47SStephan Aßmus{
35263a30a47SStephan Aßmus	fIdentityTransform = transform.IsIdentity();
35363a30a47SStephan Aßmus	if (!fIdentityTransform) {
354fd8ad3d8SStephan Aßmus		fTransform = agg::trans_affine_translation(-xOffset, -yOffset);
355fd8ad3d8SStephan Aßmus		fTransform *= agg::trans_affine(transform.sx, transform.shy,
356fd8ad3d8SStephan Aßmus			transform.shx, transform.sy, transform.tx, transform.ty);
357fd8ad3d8SStephan Aßmus		fTransform *= agg::trans_affine_translation(xOffset, yOffset);
35863a30a47SStephan Aßmus	} else {
35963a30a47SStephan Aßmus		fTransform.reset();
36063a30a47SStephan Aßmus	}
36163a30a47SStephan Aßmus}
36263a30a47SStephan Aßmus
36363a30a47SStephan Aßmus
3644569b90dSStephan Aßmus// SetHighColor
3654569b90dSStephan Aßmusvoid
3664569b90dSStephan AßmusPainter::SetHighColor(const rgb_color& color)
3674569b90dSStephan Aßmus{
368f7e1df75SStephan Aßmus	if (fPatternHandler.HighColor() == color)
36967f3be42SStephan Aßmus		return;
370eb9f93f3SStephan Aßmus	fPatternHandler.SetHighColor(color);
371eb9f93f3SStephan Aßmus	if (*(fPatternHandler.GetR5Pattern()) == B_SOLID_HIGH)
3725cf27f9bSStephan Aßmus		_SetRendererColor(color);
3734569b90dSStephan Aßmus}
3744569b90dSStephan Aßmus
375c97f4931SAxel Dörfler
3764569b90dSStephan Aßmus// SetLowColor
3774569b90dSStephan Aßmusvoid
3784569b90dSStephan AßmusPainter::SetLowColor(const rgb_color& color)
3794569b90dSStephan Aßmus{
380eb9f93f3SStephan Aßmus	fPatternHandler.SetLowColor(color);
381eb9f93f3SStephan Aßmus	if (*(fPatternHandler.GetR5Pattern()) == B_SOLID_LOW)
3825cf27f9bSStephan Aßmus		_SetRendererColor(color);
3834569b90dSStephan Aßmus}
3844569b90dSStephan Aßmus
385c97f4931SAxel Dörfler
3860896fce5SStephan Aßmus// SetDrawingMode
3870896fce5SStephan Aßmusvoid
3880896fce5SStephan AßmusPainter::SetDrawingMode(drawing_mode mode)
3890896fce5SStephan Aßmus{
3900896fce5SStephan Aßmus	if (fDrawingMode != mode) {
3910896fce5SStephan Aßmus		fDrawingMode = mode;
3920896fce5SStephan Aßmus		_UpdateDrawingMode();
3930896fce5SStephan Aßmus	}
3940896fce5SStephan Aßmus}
3950896fce5SStephan Aßmus
396fa6a00c6SStephan Aßmus
39738287e02SStephan Aßmus// SetBlendingMode
39838287e02SStephan Aßmusvoid
39938287e02SStephan AßmusPainter::SetBlendingMode(source_alpha srcAlpha, alpha_function alphaFunc)
40038287e02SStephan Aßmus{
40138287e02SStephan Aßmus	if (fAlphaSrcMode != srcAlpha || fAlphaFncMode != alphaFunc) {
40238287e02SStephan Aßmus		fAlphaSrcMode = srcAlpha;
40338287e02SStephan Aßmus		fAlphaFncMode = alphaFunc;
40438287e02SStephan Aßmus		if (fDrawingMode == B_OP_ALPHA)
40538287e02SStephan Aßmus			_UpdateDrawingMode();
40638287e02SStephan Aßmus	}
40738287e02SStephan Aßmus}
40838287e02SStephan Aßmus
409c97f4931SAxel Dörfler
41036351e2dSStephan Aßmus// SetPenSize
4114569b90dSStephan Aßmusvoid
4124569b90dSStephan AßmusPainter::SetPenSize(float size)
4134569b90dSStephan Aßmus{
41438287e02SStephan Aßmus	fPenSize = size;
41538287e02SStephan Aßmus}
41638287e02SStephan Aßmus
417c97f4931SAxel Dörfler
41838287e02SStephan Aßmus// SetStrokeMode
41938287e02SStephan Aßmusvoid
42038287e02SStephan AßmusPainter::SetStrokeMode(cap_mode lineCap, join_mode joinMode, float miterLimit)
42138287e02SStephan Aßmus{
42238287e02SStephan Aßmus	fLineCapMode = lineCap;
42338287e02SStephan Aßmus	fLineJoinMode = joinMode;
42438287e02SStephan Aßmus	fMiterLimit = miterLimit;
4254569b90dSStephan Aßmus}
4264569b90dSStephan Aßmus
427c97f4931SAxel Dörfler
428eb431663SAdrien Destuguesvoid
429eb431663SAdrien DestuguesPainter::SetFillRule(int32 fillRule)
430eb431663SAdrien Destugues{
431b74fecd7SStephan Aßmus	agg::filling_rule_e aggFillRule = fillRule == B_EVEN_ODD
432b74fecd7SStephan Aßmus		? agg::fill_even_odd : agg::fill_non_zero;
433b74fecd7SStephan Aßmus
434b74fecd7SStephan Aßmus	fRasterizer.filling_rule(aggFillRule);
435b74fecd7SStephan Aßmus	fSubpixRasterizer.filling_rule(aggFillRule);
436eb431663SAdrien Destugues}
437eb431663SAdrien Destugues
438eb431663SAdrien Destugues
4394da1508aSStephan Aßmus// SetPattern
4404da1508aSStephan Aßmusvoid
441b6a33e1dSStephan AßmusPainter::SetPattern(const pattern& p, bool drawingText)
4424da1508aSStephan Aßmus{
443eb9f93f3SStephan Aßmus	if (!(p == *fPatternHandler.GetR5Pattern()) || drawingText != fDrawingText) {
444eb9f93f3SStephan Aßmus		fPatternHandler.SetPattern(p);
445b6a33e1dSStephan Aßmus		fDrawingText = drawingText;
446b6a33e1dSStephan Aßmus		_UpdateDrawingMode(fDrawingText);
447208e6678SStephan Aßmus
448208e6678SStephan Aßmus		// update renderer color if necessary
449eb9f93f3SStephan Aßmus		if (fPatternHandler.IsSolidHigh()) {
450208e6678SStephan Aßmus			// pattern was not solid high before
451f7e1df75SStephan Aßmus			_SetRendererColor(fPatternHandler.HighColor());
452eb9f93f3SStephan Aßmus		} else if (fPatternHandler.IsSolidLow()) {
453208e6678SStephan Aßmus			// pattern was not solid low before
454f7e1df75SStephan Aßmus			_SetRendererColor(fPatternHandler.LowColor());
455208e6678SStephan Aßmus		}
4564569b90dSStephan Aßmus	}
4574569b90dSStephan Aßmus}
4584569b90dSStephan Aßmus
459c97f4931SAxel Dörfler
4606fb68b83SStephan Aßmus// SetFont
4616fb68b83SStephan Aßmusvoid
4626fb68b83SStephan AßmusPainter::SetFont(const ServerFont& font)
4636fb68b83SStephan Aßmus{
464c9d2046fSStephan Aßmus	fTextRenderer.SetFont(font);
465c97f4931SAxel Dörfler	fTextRenderer.SetAntialiasing(!(font.Flags() & B_DISABLE_ANTIALIASING));
466fe914c98SStephan Aßmus}
467fe914c98SStephan Aßmus
468c97f4931SAxel Dörfler
469fe914c98SStephan Aßmus// SetFont
470fe914c98SStephan Aßmusvoid
471fe914c98SStephan AßmusPainter::SetFont(const DrawState* state)
472fe914c98SStephan Aßmus{
473fe914c98SStephan Aßmus	fTextRenderer.SetFont(state->Font());
474c97f4931SAxel Dörfler	fTextRenderer.SetAntialiasing(!state->ForceFontAliasing()
47577fdfdfeSAxel Dörfler		&& (state->Font().Flags() & B_DISABLE_ANTIALIASING) == 0);
4766fb68b83SStephan Aßmus}
4776fb68b83SStephan Aßmus
478c97f4931SAxel Dörfler
479208e6678SStephan Aßmus// #pragma mark - drawing
4804569b90dSStephan Aßmus
481c97f4931SAxel Dörfler
4824569b90dSStephan Aßmus// StrokeLine
48338287e02SStephan Aßmusvoid
484208e6678SStephan AßmusPainter::StrokeLine(BPoint a, BPoint b)
4854569b90dSStephan Aßmus{
48638287e02SStephan Aßmus	CHECK_CLIPPING_NO_RETURN
487924b7ab2SStephan Aßmus
4888efa2a5dSStephan Aßmus	// "false" means not to do the pixel center offset,
4898efa2a5dSStephan Aßmus	// because it would mess up our optimized versions
49046b39e83SStephan Aßmus	_Align(&a, false);
49146b39e83SStephan Aßmus	_Align(&b, false);
4924569b90dSStephan Aßmus
4931a7fc527SStephan Aßmus	// first, try an optimized version
49463a30a47SStephan Aßmus	if (fPenSize == 1.0 && fIdentityTransform
495f08d5477SAdrien Destugues		&& (fDrawingMode == B_OP_COPY || fDrawingMode == B_OP_OVER)
496f08d5477SAdrien Destugues		&& fMaskedUnpackedScanline == NULL) {
497eb9f93f3SStephan Aßmus		pattern pat = *fPatternHandler.GetR5Pattern();
49852868199SStephan Aßmus		if (pat == B_SOLID_HIGH
499f7e1df75SStephan Aßmus			&& StraightLine(a, b, fPatternHandler.HighColor())) {
50052868199SStephan Aßmus			return;
50152868199SStephan Aßmus		} else if (pat == B_SOLID_LOW
502f7e1df75SStephan Aßmus			&& StraightLine(a, b, fPatternHandler.LowColor())) {
50352868199SStephan Aßmus			return;
5041a7fc527SStephan Aßmus		}
5051a7fc527SStephan Aßmus	}
506fa6a00c6SStephan Aßmus
5079ecf9d1cSIngo Weinhold	fPath.remove_all();
5089ecf9d1cSIngo Weinhold
5099ecf9d1cSIngo Weinhold	if (a == b) {
5109ecf9d1cSIngo Weinhold		// special case dots
51163a30a47SStephan Aßmus		if (fPenSize == 1.0 && !fSubpixelPrecise && fIdentityTransform) {
512779b52e5SStephan Aßmus			if (fClippingRegion->Contains(a)) {
5130ccd1db1SJulian Harnath				int dotX = (int)a.x;
5140ccd1db1SJulian Harnath				int dotY = (int)a.y;
5150ccd1db1SJulian Harnath				fBaseRenderer.translate_to_base_ren(dotX, dotY);
5160ccd1db1SJulian Harnath				fPixelFormat.blend_pixel(dotX, dotY, fRenderer.color(),
5179d570aa4SStephan Aßmus					255);
518779b52e5SStephan Aßmus			}
519779b52e5SStephan Aßmus		} else {
520779b52e5SStephan Aßmus			fPath.move_to(a.x, a.y);
521779b52e5SStephan Aßmus			fPath.line_to(a.x + 1, a.y);
522779b52e5SStephan Aßmus			fPath.line_to(a.x + 1, a.y + 1);
523779b52e5SStephan Aßmus			fPath.line_to(a.x, a.y + 1);
5249ecf9d1cSIngo Weinhold
52538287e02SStephan Aßmus			_FillPath(fPath);
526779b52e5SStephan Aßmus		}
5279ecf9d1cSIngo Weinhold	} else {
52846b39e83SStephan Aßmus		// Do the pixel center offset here
529a87c4748SStephan Aßmus		if (!fSubpixelPrecise && fmodf(fPenSize, 2.0) != 0.0) {
53046b39e83SStephan Aßmus			_Align(&a, true);
53146b39e83SStephan Aßmus			_Align(&b, true);
532ae540011SStephan Aßmus		}
533fa6a00c6SStephan Aßmus
5349ecf9d1cSIngo Weinhold		fPath.move_to(a.x, a.y);
5359ecf9d1cSIngo Weinhold		fPath.line_to(b.x, b.y);
5364569b90dSStephan Aßmus
537a87c4748SStephan Aßmus		if (!fSubpixelPrecise && fPenSize == 1.0f) {
53846b39e83SStephan Aßmus			// Tweak ends to "include" the pixel at the index,
53946b39e83SStephan Aßmus			// we need to do this in order to produce results like R5,
54046b39e83SStephan Aßmus			// where coordinates were inclusive
54146b39e83SStephan Aßmus			_StrokePath(fPath, B_SQUARE_CAP);
54246b39e83SStephan Aßmus		} else
54346b39e83SStephan Aßmus			_StrokePath(fPath);
5449ecf9d1cSIngo Weinhold	}
5454569b90dSStephan Aßmus}
5464569b90dSStephan Aßmus
547c97f4931SAxel Dörfler
5481a7fc527SStephan Aßmus// StraightLine
5491a7fc527SStephan Aßmusbool
5501a7fc527SStephan AßmusPainter::StraightLine(BPoint a, BPoint b, const rgb_color& c) const
5511a7fc527SStephan Aßmus{
552eb9f93f3SStephan Aßmus	if (!fValidClipping)
553eb9f93f3SStephan Aßmus		return false;
554eb9f93f3SStephan Aßmus
555eb9f93f3SStephan Aßmus	if (a.x == b.x) {
556eb9f93f3SStephan Aßmus		// vertical
557eb9f93f3SStephan Aßmus		uint8* dst = fBuffer.row_ptr(0);
558eb9f93f3SStephan Aßmus		uint32 bpr = fBuffer.stride();
559eb9f93f3SStephan Aßmus		int32 x = (int32)a.x;
560eb9f93f3SStephan Aßmus		dst += x * 4;
561eb9f93f3SStephan Aßmus		int32 y1 = (int32)min_c(a.y, b.y);
562eb9f93f3SStephan Aßmus		int32 y2 = (int32)max_c(a.y, b.y);
563eb9f93f3SStephan Aßmus		pixel32 color;
564eb9f93f3SStephan Aßmus		color.data8[0] = c.blue;
565eb9f93f3SStephan Aßmus		color.data8[1] = c.green;
566eb9f93f3SStephan Aßmus		color.data8[2] = c.red;
567eb9f93f3SStephan Aßmus		color.data8[3] = 255;
568eb9f93f3SStephan Aßmus		// draw a line, iterate over clipping boxes
569eb9f93f3SStephan Aßmus		fBaseRenderer.first_clip_box();
570eb9f93f3SStephan Aßmus		do {
571eb9f93f3SStephan Aßmus			if (fBaseRenderer.xmin() <= x &&
572eb9f93f3SStephan Aßmus				fBaseRenderer.xmax() >= x) {
573eb9f93f3SStephan Aßmus				int32 i = max_c(fBaseRenderer.ymin(), y1);
574eb9f93f3SStephan Aßmus				int32 end = min_c(fBaseRenderer.ymax(), y2);
575eb9f93f3SStephan Aßmus				uint8* handle = dst + i * bpr;
576eb9f93f3SStephan Aßmus				for (; i <= end; i++) {
577eb9f93f3SStephan Aßmus					*(uint32*)handle = color.data32;
578eb9f93f3