1/*
2 * Copyright 2014, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Copyright 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
6 *
7 * Class clipped_alpha_mask, a modified version of alpha_mask_u8 that can
8 * offset the mask, and has a controllable value for the area outside it.
9 */
10
11#ifndef AGG_CLIPED_ALPHA_MASK_INCLUDED
12#define AGG_CLIPED_ALPHA_MASK_INCLUDED
13
14
15#include <agg_alpha_mask_u8.h>
16#include <agg_rendering_buffer.h>
17
18
19namespace agg
20{
21	class clipped_alpha_mask
22	{
23		public:
24			typedef int8u cover_type;
25			enum cover_scale_e
26			{
27				cover_shift = 8,
28				cover_none  = 0,
29				cover_full  = 255
30			};
31
32			clipped_alpha_mask()
33				: m_xOffset(0), m_yOffset(0), m_rbuf(0), m_outside(0) {}
34			clipped_alpha_mask(rendering_buffer& rbuf)
35				: m_xOffset(0), m_yOffset(0), m_rbuf(&rbuf), m_outside(0) {}
36
37			void attach(rendering_buffer& rbuf)
38			{
39				m_rbuf = &rbuf;
40			}
41
42			void attach(rendering_buffer& rbuf, int x, int y, int8u outside)
43			{
44				m_rbuf = &rbuf;
45				m_xOffset = x;
46				m_yOffset = y;
47				m_outside = outside;
48			}
49
50			void combine_hspan(int x, int y, cover_type* dst, int num_pix) const
51			{
52				int count = num_pix;
53				cover_type* covers = dst;
54
55				bool has_inside = _set_outside(x, y, covers, count);
56				if (!has_inside)
57					return;
58
59				const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset;
60				do
61				{
62					*covers = (cover_type)((cover_full + (*covers) * (*mask))
63						>> cover_shift);
64					++covers;
65					mask += Step;
66				}
67				while(--count);
68			}
69
70			void get_hspan(int x, int y, cover_type* dst, int num_pix) const
71			{
72				int count = num_pix;
73				cover_type* covers = dst;
74
75				bool has_inside = _set_outside(x, y, covers, count);
76				if (!has_inside)
77					return;
78
79				const int8u* mask = m_rbuf->row_ptr(y) + x * Step + Offset;
80				memcpy(covers, mask, count);
81			}
82
83		private:
84			bool _set_outside(int& x, int& y, cover_type*& covers,
85				int& count) const
86			{
87				x -= m_xOffset;
88				y -= m_yOffset;
89
90				int xmax = m_rbuf->width() - 1;
91				int ymax = m_rbuf->height() - 1;
92
93				int num_pix = count;
94				cover_type* dst = covers;
95
96				if(y < 0 || y > ymax)
97				{
98					memset(dst, m_outside, num_pix * sizeof(cover_type));
99					return false;
100				}
101
102				if(x < 0)
103				{
104					count += x;
105					if(count <= 0)
106					{
107						memset(dst, m_outside, num_pix * sizeof(cover_type));
108						return false;
109					}
110					memset(covers, m_outside, -x * sizeof(cover_type));
111					covers -= x;
112					x = 0;
113				}
114
115				if(x + count > xmax)
116				{
117					int rest = x + count - xmax - 1;
118					count -= rest;
119					if(count <= 0)
120					{
121						memset(dst, m_outside, num_pix * sizeof(cover_type));
122						return false;
123					}
124					memset(covers + count, m_outside, rest * sizeof(cover_type));
125				}
126
127				return true;
128			}
129
130
131		private:
132			int m_xOffset;
133			int m_yOffset;
134
135			rendering_buffer* m_rbuf;
136			int8u m_outside;
137
138			static const int Step = 1;
139			static const int Offset = 0;
140	};
141}
142
143
144#endif
145