1 | /* GDK - The GIMP Drawing Kit |
2 | * Copyright (C) 2000 Red Hat, Inc. |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | #include "config.h" |
19 | |
20 | #include "gdkpango.h" |
21 | |
22 | #include "gdkintl.h" |
23 | |
24 | #include <math.h> |
25 | #include <pango/pangocairo.h> |
26 | |
27 | |
28 | /* Get a clip region to draw only part of a layout. index_ranges |
29 | * contains alternating range starts/stops. The region is the |
30 | * region which contains the given ranges, i.e. if you draw with the |
31 | * region as clip, only the given ranges are drawn. |
32 | */ |
33 | static cairo_region_t* |
34 | layout_iter_get_line_clip_region (PangoLayoutIter *iter, |
35 | int x_origin, |
36 | int y_origin, |
37 | const int *index_ranges, |
38 | int n_ranges) |
39 | { |
40 | PangoLayoutLine *line; |
41 | cairo_region_t *clip_region; |
42 | PangoRectangle logical_rect; |
43 | int baseline; |
44 | int i; |
45 | |
46 | line = pango_layout_iter_get_line_readonly (iter); |
47 | |
48 | clip_region = cairo_region_create (); |
49 | |
50 | pango_layout_iter_get_line_extents (iter, NULL, logical_rect: &logical_rect); |
51 | baseline = pango_layout_iter_get_baseline (iter); |
52 | |
53 | i = 0; |
54 | while (i < n_ranges) |
55 | { |
56 | int *pixel_ranges = NULL; |
57 | int n_pixel_ranges = 0; |
58 | int j; |
59 | |
60 | /* Note that get_x_ranges returns layout coordinates |
61 | */ |
62 | if (index_ranges[i*2+1] >= pango_layout_line_get_start_index (line) && |
63 | index_ranges[i*2] < pango_layout_line_get_start_index (line) + pango_layout_line_get_length (line)) |
64 | pango_layout_line_get_x_ranges (line, |
65 | start_index: index_ranges[i*2], |
66 | end_index: index_ranges[i*2+1], |
67 | ranges: &pixel_ranges, n_ranges: &n_pixel_ranges); |
68 | |
69 | for (j = 0; j < n_pixel_ranges; j++) |
70 | { |
71 | GdkRectangle rect; |
72 | int x_off, y_off; |
73 | |
74 | x_off = PANGO_PIXELS (pixel_ranges[2*j] - logical_rect.x); |
75 | y_off = PANGO_PIXELS (baseline - logical_rect.y); |
76 | |
77 | rect.x = x_origin + x_off; |
78 | rect.y = y_origin - y_off; |
79 | rect.width = PANGO_PIXELS (pixel_ranges[2*j + 1] - logical_rect.x) - x_off; |
80 | rect.height = PANGO_PIXELS (baseline - logical_rect.y + logical_rect.height) - y_off; |
81 | |
82 | cairo_region_union_rectangle (dst: clip_region, rectangle: &rect); |
83 | } |
84 | |
85 | g_free (mem: pixel_ranges); |
86 | ++i; |
87 | } |
88 | return clip_region; |
89 | } |
90 | |
91 | /** |
92 | * gdk_pango_layout_line_get_clip_region: (skip) |
93 | * @line: a `PangoLayoutLine` |
94 | * @x_origin: X pixel where you intend to draw the layout line with this clip |
95 | * @y_origin: baseline pixel where you intend to draw the layout line with this clip |
96 | * @index_ranges: (array): array of byte indexes into the layout, where even |
97 | * members of array are start indexes and odd elements are end indexes |
98 | * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges |
99 | * |
100 | * Obtains a clip region which contains the areas where the given |
101 | * ranges of text would be drawn. |
102 | * |
103 | * @x_origin and @y_origin are the top left position of the layout. |
104 | * @index_ranges should contain ranges of bytes in the layout’s text. |
105 | * The clip region will include space to the left or right of the line |
106 | * (to the layout bounding box) if you have indexes above or below the |
107 | * indexes contained inside the line. This is to draw the selection all |
108 | * the way to the side of the layout. However, the clip region is in line |
109 | * coordinates, not layout coordinates. |
110 | * |
111 | * Note that the regions returned correspond to logical extents of the text |
112 | * ranges, not ink extents. So the drawn line may in fact touch areas out of |
113 | * the clip region. The clip region is mainly useful for highlightling parts |
114 | * of text, such as when text is selected. |
115 | * |
116 | * Returns: a clip region containing the given ranges |
117 | */ |
118 | cairo_region_t* |
119 | gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line, |
120 | int x_origin, |
121 | int y_origin, |
122 | const int *index_ranges, |
123 | int n_ranges) |
124 | { |
125 | cairo_region_t *clip_region; |
126 | PangoLayoutIter *iter; |
127 | |
128 | g_return_val_if_fail (line != NULL, NULL); |
129 | g_return_val_if_fail (index_ranges != NULL, NULL); |
130 | |
131 | iter = pango_layout_get_iter (layout: line->layout); |
132 | while (pango_layout_iter_get_line_readonly (iter) != line) |
133 | pango_layout_iter_next_line (iter); |
134 | |
135 | clip_region = layout_iter_get_line_clip_region(iter, x_origin, y_origin, index_ranges, n_ranges); |
136 | |
137 | pango_layout_iter_free (iter); |
138 | |
139 | return clip_region; |
140 | } |
141 | |
142 | /** |
143 | * gdk_pango_layout_get_clip_region: (skip) |
144 | * @layout: a `PangoLayout` |
145 | * @x_origin: X pixel where you intend to draw the layout with this clip |
146 | * @y_origin: Y pixel where you intend to draw the layout with this clip |
147 | * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes |
148 | * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges |
149 | * |
150 | * Obtains a clip region which contains the areas where the given ranges |
151 | * of text would be drawn. |
152 | * |
153 | * @x_origin and @y_origin are the top left point to center the layout. |
154 | * @index_ranges should contain ranges of bytes in the layout’s text. |
155 | * |
156 | * Note that the regions returned correspond to logical extents of the text |
157 | * ranges, not ink extents. So the drawn layout may in fact touch areas out of |
158 | * the clip region. The clip region is mainly useful for highlightling parts |
159 | * of text, such as when text is selected. |
160 | * |
161 | * Returns: a clip region containing the given ranges |
162 | */ |
163 | cairo_region_t* |
164 | gdk_pango_layout_get_clip_region (PangoLayout *layout, |
165 | int x_origin, |
166 | int y_origin, |
167 | const int *index_ranges, |
168 | int n_ranges) |
169 | { |
170 | PangoLayoutIter *iter; |
171 | cairo_region_t *clip_region; |
172 | |
173 | g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL); |
174 | g_return_val_if_fail (index_ranges != NULL, NULL); |
175 | |
176 | clip_region = cairo_region_create (); |
177 | |
178 | iter = pango_layout_get_iter (layout); |
179 | |
180 | do |
181 | { |
182 | PangoRectangle logical_rect; |
183 | cairo_region_t *line_region; |
184 | int baseline; |
185 | |
186 | pango_layout_iter_get_line_extents (iter, NULL, logical_rect: &logical_rect); |
187 | baseline = pango_layout_iter_get_baseline (iter); |
188 | |
189 | line_region = layout_iter_get_line_clip_region(iter, |
190 | x_origin: x_origin + PANGO_PIXELS (logical_rect.x), |
191 | y_origin: y_origin + PANGO_PIXELS (baseline), |
192 | index_ranges, |
193 | n_ranges); |
194 | |
195 | cairo_region_union (dst: clip_region, other: line_region); |
196 | cairo_region_destroy (region: line_region); |
197 | } |
198 | while (pango_layout_iter_next_line (iter)); |
199 | |
200 | pango_layout_iter_free (iter); |
201 | |
202 | return clip_region; |
203 | } |
204 | |