1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* This file is part of the GtkHTML library.
3  *
4  * Copyright (C) 2001, Ximian, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20 */
21 
22 #include <glib.h>
23 #include <string.h>
24 #include <math.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include "htmlstyle.h"
28 #include "htmlshape.h"
29 
30 struct _HTMLShape {
31 	HTMLShapeType type;
32 	gchar *url;
33 	gchar *target;
34 	GPtrArray *coords;
35 };
36 
37 static HTMLLength *
parse_length(const gchar ** str)38 parse_length (const gchar **str)
39 {
40 	const gchar *cur = *str;
41 	HTMLLength *len = g_new0 (HTMLLength, 1);
42 
43 	/* g_warning ("begin \"%s\"", *str); */
44 
45 	while (isspace (*cur)) cur++;
46 
47 	len->val = atoi (cur);
48 	len->type = HTML_LENGTH_TYPE_PIXELS;
49 
50 	while (isdigit (*cur) || *cur == '-') cur++;
51 
52 	switch (*cur) {
53 	case '*':
54 		if (len->val == 0)
55 			len->val = 1;
56 		len->type = HTML_LENGTH_TYPE_FRACTION;
57 		cur++;
58 		break;
59 	case '%':
60 		len->type = HTML_LENGTH_TYPE_PERCENT;
61 		cur++;
62 		break;
63 	}
64 
65 	if (cur <= *str) {
66 		g_free (len);
67 		return NULL;
68 	}
69 
70 	/* g_warning ("length len->val=%d, len->type=%d", len->val, len->type); */
71 	*str = cur;
72 	cur = strstr (cur, ",");
73 	if (cur) {
74 		cur++;
75 		*str = cur;
76 	}
77 
78 	return len;
79 }
80 
81 void
html_length_array_parse(GPtrArray * array,const gchar * str)82 html_length_array_parse (GPtrArray *array,
83                          const gchar *str)
84 {
85 	HTMLLength *length;
86 
87 	if (str == NULL)
88 		return;
89 
90 	while ((length = parse_length (&str)))
91 	       g_ptr_array_add (array, length);
92 }
93 
94 void
html_length_array_destroy(GPtrArray * array)95 html_length_array_destroy (GPtrArray *array)
96 {
97 	gint i;
98 
99 	for (i = 0; i < array->len; i++)
100 		g_free (g_ptr_array_index (array, i));
101 }
102 
103 #define HTML_DIST(x,y) (gint)sqrt((x)*(x) + (y)*(y))
104 
105 gboolean
html_shape_point(HTMLShape * shape,gint x,gint y)106 html_shape_point (HTMLShape *shape,
107                   gint x,
108                   gint y)
109 {
110 	gint i;
111 	gint j = 0;
112 	gint odd = 0;
113 
114 	HTMLLength **poly = (HTMLLength **) shape->coords->pdata;
115 
116 	/*
117 	 * TODO: Add support for percentage lengths, The information is stored
118 	 * so it is simply a matter of modifying the point routine to know the
119 	 * the overall size, then scaling the values.
120 	 */
121 
122 	switch (shape->type) {
123 	case HTML_SHAPE_RECT:
124 		if ((x >= poly[0]->val)
125 		    && (x <= poly[2]->val)
126 		    && (y >= poly[1]->val)
127 		    && (y <= poly[3]->val))
128 			return TRUE;
129 		break;
130 	case HTML_SHAPE_CIRCLE:
131 		if (HTML_DIST (x - poly[0]->val, y - poly[1]->val) <= poly[2]->val)
132 			return TRUE;
133 
134 		break;
135 	case HTML_SHAPE_POLY:
136 		for (i = 0; i < shape->coords->len; i+=2) {
137 			j+=2;
138 			if (j == shape->coords->len)
139 				j = 0;
140 
141 			if ((poly[i + 1]->val < y && poly[j + 1]->val >= y)
142 			    || (poly[j + 1]->val < y && poly[i + 1]->val >= y)) {
143 
144 				if (poly[i]->val + (y - poly[i + 1]->val)
145 				    / (poly[j + 1]->val - poly[i + 1]->val)
146 				    * (poly[j]->val - poly[i]->val) < x) {
147 					odd = !odd;
148 				}
149 			}
150 		}
151 		return odd;
152 		break;
153 	case HTML_SHAPE_DEFAULT:
154 		return TRUE;
155 		break;
156 	}
157 	return FALSE;
158 }
159 
160 static HTMLShapeType
parse_shape_type(gchar * token)161 parse_shape_type (gchar *token)
162 {
163 	HTMLShapeType type = HTML_SHAPE_RECT;
164 
165 	if (!token || g_ascii_strncasecmp (token, "rect", 4) == 0)
166 		type = HTML_SHAPE_RECT;
167 	else if (g_ascii_strncasecmp (token, "poly", 4) == 0)
168 		type = HTML_SHAPE_POLY;
169 	else if (g_ascii_strncasecmp (token, "circle", 6) == 0)
170 		type = HTML_SHAPE_CIRCLE;
171 	else if (g_ascii_strncasecmp (token, "default", 7) == 0)
172 		type = HTML_SHAPE_DEFAULT;
173 
174 	return type;
175 }
176 
177 gchar *
html_shape_get_url(HTMLShape * shape)178 html_shape_get_url (HTMLShape *shape)
179 {
180 	return shape->url;
181 }
182 
183 HTMLShape *
html_shape_new(gchar * type_str,gchar * coords,gchar * url,gchar * target)184 html_shape_new (gchar *type_str,
185                 gchar *coords,
186                 gchar *url,
187                 gchar *target)
188 {
189 	HTMLShape *shape;
190 	HTMLShapeType type = parse_shape_type (type_str);
191 
192 	if (coords == NULL && type != HTML_SHAPE_DEFAULT)
193 		return NULL;
194 
195 	shape = g_new (HTMLShape, 1);
196 
197 	shape->type = type;
198 	shape->url = g_strdup (url);
199 	shape->target = g_strdup (target);
200 	shape->coords = g_ptr_array_new ();
201 
202 	html_length_array_parse (shape->coords, coords);
203 
204 	switch (shape->type) {
205 	case HTML_SHAPE_RECT:
206 		while (shape->coords->len < 4)
207 			g_ptr_array_add (shape->coords,
208 					 g_new0 (HTMLLength, 1));
209 	case HTML_SHAPE_CIRCLE:
210 		while (shape->coords->len < 3)
211 			g_ptr_array_add (shape->coords,
212 					 g_new0 (HTMLLength, 1));
213 	case HTML_SHAPE_POLY:
214 		if (shape->coords->len % 2)
215 			g_ptr_array_add (shape->coords,
216 					 g_new0 (HTMLLength, 1));
217 
218 		break;
219 	default:
220 		break;
221 	}
222 	return shape;
223 }
224 
225 void
html_shape_destroy(HTMLShape * shape)226 html_shape_destroy (HTMLShape *shape)
227 {
228 	g_free (shape->url);
229 	g_free (shape->target);
230 	html_length_array_destroy (shape->coords);
231 
232 	g_free (shape);
233 }
234 
235