# HG changeset patch
# User Thomas Liebetraut <thomas@tommie-lie.de>
# Date 1396195767 -7200
#      Sun Mar 30 18:09:27 2014 +0200
# Node ID 48de07d940ed928d89b67b4d47bc53b8adb65622
# Parent  eee239b048d4aca26cf7b59bba4a5cafd4dfb3a4
Add EvAnnotationTextMarkup class.

This base class should be used for all text markup
annotations like text highlighting, underlining, etc.

diff -r eee239b048d4 -r 48de07d940ed libdocument/ev-annotation.c
--- a/libdocument/ev-annotation.c	Sun Mar 30 13:23:55 2014 +0200
+++ b/libdocument/ev-annotation.c	Sun Mar 30 18:09:27 2014 +0200
@@ -71,9 +71,20 @@
 	EvAnnotationClass parent_class;
 };
 
-static void ev_annotation_markup_default_init          (EvAnnotationMarkupInterface *iface);
-static void ev_annotation_text_markup_iface_init       (EvAnnotationMarkupInterface *iface);
-static void ev_annotation_attachment_markup_iface_init (EvAnnotationMarkupInterface *iface);
+struct _EvAnnotationTextMarkup {
+	EvAnnotation parent;
+
+	GArray *quadrilaterals;
+};
+
+struct _EvAnnotationTextMarkupClass {
+	EvAnnotationClass parent_class;
+};
+
+static void ev_annotation_markup_default_init           (EvAnnotationMarkupInterface *iface);
+static void ev_annotation_text_markup_iface_init        (EvAnnotationMarkupInterface *iface);
+static void ev_annotation_attachment_markup_iface_init  (EvAnnotationMarkupInterface *iface);
+static void ev_annotation_text_markup_markup_iface_init (EvAnnotationMarkupInterface *iface);
 
 /* EvAnnotation */
 enum {
@@ -108,6 +119,11 @@
 	PROP_ATTACHMENT_ATTACHMENT = PROP_MARKUP_POPUP_IS_OPEN + 1
 };
 
+/* EvAnnotationTextMarkup */
+enum {
+	PROP_TEXT_MARKUP_QUADRILATERALS = PROP_MARKUP_POPUP_IS_OPEN + 1
+};
+
 G_DEFINE_ABSTRACT_TYPE (EvAnnotation, ev_annotation, G_TYPE_OBJECT)
 G_DEFINE_INTERFACE (EvAnnotationMarkup, ev_annotation_markup, EV_TYPE_ANNOTATION)
 G_DEFINE_TYPE_WITH_CODE (EvAnnotationText, ev_annotation_text, EV_TYPE_ANNOTATION,
@@ -121,6 +137,12 @@
 					ev_annotation_attachment_markup_iface_init);
 	 });
 
+G_DEFINE_TYPE_WITH_CODE (EvAnnotationTextMarkup, ev_annotation_text_markup, EV_TYPE_ANNOTATION,
+	 {
+		 G_IMPLEMENT_INTERFACE (EV_TYPE_ANNOTATION_MARKUP,
+					ev_annotation_text_markup_markup_iface_init);
+	 });
+
 /* EvAnnotation */
 static void
 ev_annotation_finalize (GObject *object)
@@ -1350,3 +1372,182 @@
 {
 	g_free (quad);
 }
+
+/* EvAnnotationTextMarkup */
+static void
+ev_annotation_text_markup_finalize (GObject *object)
+{
+	EvAnnotationTextMarkup *annot = EV_ANNOTATION_TEXT_MARKUP (object);
+
+	if (annot->quadrilaterals) {
+		g_object_unref(annot->quadrilaterals);
+		annot->quadrilaterals = NULL;
+	}
+}
+
+static void
+ev_annotation_text_markup_init (EvAnnotationTextMarkup *annot)
+{
+	annot->quadrilaterals = g_array_new(FALSE, TRUE, sizeof(EvQuadrilateral));
+}
+
+static gboolean
+ev_annotation_text_markup_impl_is_location_in_area (EvAnnotation *annot,
+						    gdouble       x,
+						    gdouble       y)
+{
+	EvAnnotationTextMarkup *tm_annot = EV_ANNOTATION_TEXT_MARKUP (annot);
+	EvAnnotationClass *p_class;
+	gboolean in_bounding_rect = FALSE;
+	GArray *quadrilaterals = NULL;
+
+	p_class = EV_ANNOTATION_CLASS (ev_annotation_text_markup_parent_class);
+	in_bounding_rect = p_class->is_location_in_area (annot, x, y);
+	if (!in_bounding_rect) {
+		return FALSE;
+	}
+
+	quadrilaterals = tm_annot->quadrilaterals;
+	if (quadrilaterals->len == 0) {
+		return TRUE;
+	} else {
+		int i;
+		for (i = 0; i < quadrilaterals->len; ++i) {
+			EvQuadrilateral quad = g_array_index(quadrilaterals,
+							     EvQuadrilateral,
+							     i);
+			/*
+			 * This only works for convex quadrilaterals!
+			 *
+			 * The coordinates within a quadrilateral are
+			 * defined counter-clockwise.
+			 * If the point x,y is on the left of each edge of
+			 * the quadrilateral, the point is inside the
+			 * quadrilateral.
+			 *
+			 * To test if the point P is left of a line from
+			 * A to B, first translate A and B by -P (to make
+			 * P the new point of origin).
+			 * Then consider the angle alpha between A and B:
+			 * if sin(alpha) >= 0 then the point/origin is
+			 * left of the line AB.
+			 *
+			 * 0 <= sin(alpha) = -cos(alpha + pi/2) ~ -dotP(A',B'')
+			 * where A'=A-P, B'=B-P and B''=B' rotated by pi/2.
+			 *
+			 * Note that for these calculations evince's
+			 * coordinate system is flipped vertically
+			 * (y-axis downwards)!
+			 */
+			if (((quad.p2.x - x) * (quad.p1.y - y) - (quad.p1.x - x) * (quad.p2.y - y) >= 0) &&
+			    ((quad.p3.x - x) * (quad.p2.y - y) - (quad.p2.x - x) * (quad.p3.y - y) >= 0) &&
+			    ((quad.p4.x - x) * (quad.p3.y - y) - (quad.p3.x - x) * (quad.p4.y - y) >= 0) &&
+			    ((quad.p1.x - x) * (quad.p4.y - y) - (quad.p4.x - x) * (quad.p1.y - y) >= 0)) {
+				return TRUE;
+			}
+		}
+	}
+	return FALSE;
+}
+
+static void
+ev_annotation_text_markup_set_property (GObject      *object,
+				        guint         prop_id,
+				        const GValue *value,
+				        GParamSpec   *pspec)
+{
+	EvAnnotationTextMarkup *annot = EV_ANNOTATION_TEXT_MARKUP (object);
+
+	if (prop_id < PROP_TEXT_MARKUP_QUADRILATERALS) {
+		ev_annotation_markup_set_property (object, prop_id, value, pspec);
+		return;
+	}
+
+	switch (prop_id) {
+	case PROP_TEXT_MARKUP_QUADRILATERALS:
+		ev_annotation_text_markup_set_quadrilaterals (annot,
+		                                              g_value_get_boxed (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static void
+ev_annotation_text_markup_get_property (GObject    *object,
+				        guint       prop_id,
+				        GValue     *value,
+				        GParamSpec *pspec)
+{
+	EvAnnotationTextMarkup *annot = EV_ANNOTATION_TEXT_MARKUP (object);
+
+	if (prop_id < PROP_TEXT_MARKUP_QUADRILATERALS) {
+		ev_annotation_markup_get_property (object, prop_id, value, pspec);
+		return;
+	}
+
+	switch (prop_id) {
+	case PROP_TEXT_MARKUP_QUADRILATERALS:
+		g_value_take_boxed(value, ev_annotation_text_markup_get_quadrilaterals(annot));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static void
+ev_annotation_text_markup_class_init (EvAnnotationTextMarkupClass *klass)
+{
+	GObjectClass *g_object_class = G_OBJECT_CLASS (klass);
+	EvAnnotationClass *ev_annotation_class = EV_ANNOTATION_CLASS (klass);
+
+	ev_annotation_markup_class_install_properties (g_object_class);
+
+	g_object_class->finalize = ev_annotation_text_markup_finalize;
+	g_object_class->set_property = ev_annotation_text_markup_set_property;
+	g_object_class->get_property = ev_annotation_text_markup_get_property;
+
+	ev_annotation_class->is_location_in_area = ev_annotation_text_markup_impl_is_location_in_area;
+
+	g_object_class_install_property (g_object_class,
+					 PROP_TEXT_MARKUP_QUADRILATERALS,
+					 g_param_spec_boxed ("quadrilaterals",
+							     "Quadrilaterlas",
+							     "The quadrilaterals of the annotation",
+							     G_TYPE_ARRAY,
+							     G_PARAM_READWRITE |
+                                                             G_PARAM_STATIC_STRINGS));
+}
+
+static void
+ev_annotation_text_markup_markup_iface_init (EvAnnotationMarkupInterface *iface)
+{
+}
+
+GArray*
+ev_annotation_text_markup_get_quadrilaterals (EvAnnotationTextMarkup* annot)
+{
+	GArray *result = g_array_sized_new (FALSE, FALSE,
+					    sizeof(EvQuadrilateral),
+					    annot->quadrilaterals->len);
+	g_array_append_vals (result, annot->quadrilaterals->data,
+			     annot->quadrilaterals->len);
+
+	return result;
+}
+
+gboolean
+ev_annotation_text_markup_set_quadrilaterals (EvAnnotationTextMarkup *annot,
+                                              GArray *arr)
+{
+	g_return_val_if_fail(arr != NULL, FALSE);
+	g_return_val_if_fail(arr->len > 0, FALSE);
+
+	if (annot->quadrilaterals->len)
+		g_array_remove_range (annot->quadrilaterals, 0, annot->quadrilaterals->len);
+
+	g_array_append_vals (annot->quadrilaterals, arr->data, arr->len);
+
+	return TRUE;
+}
+
diff -r eee239b048d4 -r 48de07d940ed libdocument/ev-annotation.h
--- a/libdocument/ev-annotation.h	Sun Mar 30 13:23:55 2014 +0200
+++ b/libdocument/ev-annotation.h	Sun Mar 30 18:09:27 2014 +0200
@@ -85,6 +85,15 @@
 #define EV_IS_ANNOTATION_ATTACHMENT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_ANNOTATION_ATTACHMENT))
 #define EV_ANNOTATION_ATTACHMENT_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_ANNOTATION_ATTACHMENT, EvAnnotationAttachmentClass))
 
+/* EvAnnotationTextMarkup */
+#define EV_TYPE_ANNOTATION_TEXT_MARKUP              (ev_annotation_text_markup_get_type())
+#define EV_ANNOTATION_TEXT_MARKUP(object)           (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_ANNOTATION_TEXT_MARKUP, EvAnnotationTextMarkup))
+#define EV_ANNOTATION_TEXT_MARKUP_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_ANNOTATION_TEXT_MARKUP, EvAnnotationTextMarkupClass))
+#define EV_IS_ANNOTATION_TEXT_MARKUP(object)        (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_ANNOTATION_TEXT_MARKUP))
+#define EV_IS_ANNOTATION_TEXT_MARKUP_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_ANNOTATION_TEXT_MARKUP))
+#define EV_ANNOTATION_TEXT_MARKUP_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_ANNOTATION_TEXT_MARKUP, EvAnnotationTextMarkupClass))
+
+
 typedef struct _EvAnnotation                EvAnnotation;
 typedef struct _EvAnnotationClass           EvAnnotationClass;
 
@@ -97,6 +106,9 @@
 typedef struct _EvAnnotationAttachment      EvAnnotationAttachment;
 typedef struct _EvAnnotationAttachmentClass EvAnnotationAttachmentClass;
 
+typedef struct _EvAnnotationTextMarkup      EvAnnotationTextMarkup;
+typedef struct _EvAnnotationTextMarkupClass EvAnnotationTextMarkupClass;
+
 typedef enum {
 	EV_ANNOTATION_TYPE_UNKNOWN,
 	EV_ANNOTATION_TYPE_TEXT,
@@ -188,6 +200,12 @@
 EvAttachment        *ev_annotation_attachment_get_attachment (EvAnnotationAttachment *annot);
 gboolean             ev_annotation_attachment_set_attachment (EvAnnotationAttachment *annot,
 							      EvAttachment           *attachment);
+/* EvAnnotationTextMarkup */
+GType                ev_annotation_text_markup_get_type           (void) G_GNUC_CONST;
+GArray              *ev_annotation_text_markup_get_quadrilaterals (EvAnnotationTextMarkup *annot);
+gboolean             ev_annotation_text_markup_set_quadrilaterals (EvAnnotationTextMarkup *annot,
+                                                                   GArray *arr);
+
 
 G_END_DECLS
 
