You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

906 lines
27 KiB

  1. /*
  2. * shaped texture
  3. *
  4. * An actor to draw a texture clipped to a list of rectangles
  5. *
  6. * Authored By Neil Roberts <neil@linux.intel.com>
  7. *
  8. * Copyright (C) 2008 Intel Corporation
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License as
  12. * published by the Free Software Foundation; either version 2 of the
  13. * License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful, but
  16. * WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA
  23. * 02110-1335, USA.
  24. */
  25. /**
  26. * SECTION:meta-shaped-texture
  27. * @title: MetaShapedTexture
  28. * @short_description: An actor to draw a masked texture.
  29. */
  30. #include <config.h>
  31. #define CLUTTER_ENABLE_EXPERIMENTAL_API
  32. #define COGL_ENABLE_EXPERIMENTAL_API
  33. #include <meta/meta-shaped-texture.h>
  34. #include "meta-texture-tower.h"
  35. #include "meta-texture-rectangle.h"
  36. #include "cogl-utils.h"
  37. #include <clutter/clutter.h>
  38. #include <cogl/cogl.h>
  39. #include <cogl/cogl-texture-pixmap-x11.h>
  40. #include <gdk/gdk.h> /* for gdk_rectangle_intersect() */
  41. #include <string.h>
  42. static void meta_shaped_texture_dispose (GObject *object);
  43. static void meta_shaped_texture_paint (ClutterActor *actor);
  44. static void meta_shaped_texture_pick (ClutterActor *actor,
  45. const ClutterColor *color);
  46. static void meta_shaped_texture_get_preferred_width (ClutterActor *self,
  47. gfloat for_height,
  48. gfloat *min_width_p,
  49. gfloat *natural_width_p);
  50. static void meta_shaped_texture_get_preferred_height (ClutterActor *self,
  51. gfloat for_width,
  52. gfloat *min_height_p,
  53. gfloat *natural_height_p);
  54. static void meta_shaped_texture_dirty_mask (MetaShapedTexture *stex);
  55. static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume);
  56. G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture,
  57. CLUTTER_TYPE_ACTOR);
  58. #define META_SHAPED_TEXTURE_GET_PRIVATE(obj) \
  59. (G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_SHAPED_TEXTURE, \
  60. MetaShapedTexturePrivate))
  61. struct _MetaShapedTexturePrivate
  62. {
  63. MetaTextureTower *paint_tower;
  64. Pixmap pixmap;
  65. CoglHandle texture;
  66. CoglHandle mask_texture;
  67. CoglHandle material;
  68. CoglHandle material_unshaped;
  69. cairo_region_t *clip_region;
  70. cairo_region_t *shape_region;
  71. cairo_region_t *overlay_region;
  72. cairo_path_t *overlay_path;
  73. guint tex_width, tex_height;
  74. guint mask_width, mask_height;
  75. guint create_mipmaps : 1;
  76. };
  77. static void
  78. meta_shaped_texture_class_init (MetaShapedTextureClass *klass)
  79. {
  80. GObjectClass *gobject_class = (GObjectClass *) klass;
  81. ClutterActorClass *actor_class = (ClutterActorClass *) klass;
  82. gobject_class->dispose = meta_shaped_texture_dispose;
  83. actor_class->get_preferred_width = meta_shaped_texture_get_preferred_width;
  84. actor_class->get_preferred_height = meta_shaped_texture_get_preferred_height;
  85. actor_class->paint = meta_shaped_texture_paint;
  86. actor_class->pick = meta_shaped_texture_pick;
  87. actor_class->get_paint_volume = meta_shaped_texture_get_paint_volume;
  88. g_type_class_add_private (klass, sizeof (MetaShapedTexturePrivate));
  89. }
  90. static void
  91. meta_shaped_texture_init (MetaShapedTexture *self)
  92. {
  93. MetaShapedTexturePrivate *priv;
  94. priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
  95. priv->shape_region = NULL;
  96. priv->overlay_path = NULL;
  97. priv->overlay_region = NULL;
  98. priv->paint_tower = meta_texture_tower_new ();
  99. priv->texture = COGL_INVALID_HANDLE;
  100. priv->mask_texture = COGL_INVALID_HANDLE;
  101. priv->create_mipmaps = TRUE;
  102. }
  103. static void
  104. meta_shaped_texture_dispose (GObject *object)
  105. {
  106. MetaShapedTexture *self = (MetaShapedTexture *) object;
  107. MetaShapedTexturePrivate *priv = self->priv;
  108. if (priv->paint_tower)
  109. meta_texture_tower_free (priv->paint_tower);
  110. priv->paint_tower = NULL;
  111. meta_shaped_texture_dirty_mask (self);
  112. if (priv->material != COGL_INVALID_HANDLE)
  113. {
  114. cogl_handle_unref (priv->material);
  115. priv->material = COGL_INVALID_HANDLE;
  116. }
  117. if (priv->material_unshaped != COGL_INVALID_HANDLE)
  118. {
  119. cogl_handle_unref (priv->material_unshaped);
  120. priv->material_unshaped = COGL_INVALID_HANDLE;
  121. }
  122. if (priv->texture != COGL_INVALID_HANDLE)
  123. {
  124. cogl_handle_unref (priv->texture);
  125. priv->texture = COGL_INVALID_HANDLE;
  126. }
  127. meta_shaped_texture_set_shape_region (self, NULL);
  128. meta_shaped_texture_set_clip_region (self, NULL);
  129. meta_shaped_texture_set_overlay_path (self, NULL, NULL);
  130. G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
  131. }
  132. static void
  133. meta_shaped_texture_dirty_mask (MetaShapedTexture *stex)
  134. {
  135. MetaShapedTexturePrivate *priv = stex->priv;
  136. if (priv->mask_texture != COGL_INVALID_HANDLE)
  137. {
  138. cogl_handle_unref (priv->mask_texture);
  139. priv->mask_texture = COGL_INVALID_HANDLE;
  140. }
  141. if (priv->material != COGL_INVALID_HANDLE)
  142. cogl_material_set_layer (priv->material, 1, COGL_INVALID_HANDLE);
  143. }
  144. static void
  145. install_overlay_path (MetaShapedTexture *stex,
  146. guchar *mask_data,
  147. int tex_width,
  148. int tex_height,
  149. int stride)
  150. {
  151. MetaShapedTexturePrivate *priv = stex->priv;
  152. int i, n_rects;
  153. cairo_t *cr;
  154. cairo_rectangle_int_t rect;
  155. cairo_surface_t *surface;
  156. if (priv->overlay_region == NULL)
  157. return;
  158. surface = cairo_image_surface_create_for_data (mask_data,
  159. CAIRO_FORMAT_A8,
  160. tex_width,
  161. tex_height,
  162. stride);
  163. cr = cairo_create (surface);
  164. cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
  165. n_rects = cairo_region_num_rectangles (priv->overlay_region);
  166. for (i = 0; i < n_rects; i++)
  167. {
  168. cairo_region_get_rectangle (priv->overlay_region, i, &rect);
  169. cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
  170. }
  171. cairo_fill_preserve (cr);
  172. if (priv->overlay_path == NULL)
  173. {
  174. /* If we have an overlay region but not an overlay path, then we
  175. * just need to clear the rectangles in the overlay region. */
  176. goto out;
  177. }
  178. cairo_clip (cr);
  179. cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
  180. cairo_set_source_rgba (cr, 1, 1, 1, 1);
  181. cairo_append_path (cr, priv->overlay_path);
  182. cairo_fill (cr);
  183. out:
  184. cairo_destroy (cr);
  185. cairo_surface_destroy (surface);
  186. }
  187. static void
  188. meta_shaped_texture_ensure_mask (MetaShapedTexture *stex)
  189. {
  190. MetaShapedTexturePrivate *priv = stex->priv;
  191. CoglHandle paint_tex;
  192. guint tex_width, tex_height;
  193. paint_tex = priv->texture;
  194. if (paint_tex == COGL_INVALID_HANDLE)
  195. return;
  196. tex_width = cogl_texture_get_width (paint_tex);
  197. tex_height = cogl_texture_get_height (paint_tex);
  198. /* If the mask texture we have was created for a different size then
  199. recreate it */
  200. if (priv->mask_texture != COGL_INVALID_HANDLE
  201. && (priv->mask_width != tex_width || priv->mask_height != tex_height))
  202. meta_shaped_texture_dirty_mask (stex);
  203. /* If we don't have a mask texture yet then create one */
  204. if (priv->mask_texture == COGL_INVALID_HANDLE)
  205. {
  206. guchar *mask_data;
  207. int i;
  208. int n_rects;
  209. int stride;
  210. /* If we have no shape region and no (or an empty) overlay region, we
  211. * don't need to create a full mask texture, so quit early. */
  212. if (priv->shape_region == NULL &&
  213. (priv->overlay_region == NULL ||
  214. cairo_region_num_rectangles (priv->overlay_region) == 0))
  215. {
  216. return;
  217. }
  218. stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, tex_width);
  219. /* Create data for an empty image */
  220. mask_data = g_malloc0 (stride * tex_height);
  221. n_rects = cairo_region_num_rectangles (priv->shape_region);
  222. /* Fill in each rectangle. */
  223. for (i = 0; i < n_rects; i ++)
  224. {
  225. cairo_rectangle_int_t rect;
  226. cairo_region_get_rectangle (priv->shape_region, i, &rect);
  227. gint x1 = rect.x, x2 = x1 + rect.width;
  228. gint y1 = rect.y, y2 = y1 + rect.height;
  229. guchar *p;
  230. /* Clip the rectangle to the size of the texture */
  231. x1 = CLAMP (x1, 0, (gint) tex_width - 1);
  232. x2 = CLAMP (x2, x1, (gint) tex_width);
  233. y1 = CLAMP (y1, 0, (gint) tex_height - 1);
  234. y2 = CLAMP (y2, y1, (gint) tex_height);
  235. /* Fill the rectangle */
  236. for (p = mask_data + y1 * stride + x1;
  237. y1 < y2;
  238. y1++, p += stride)
  239. memset (p, 255, x2 - x1);
  240. }
  241. install_overlay_path (stex, mask_data, tex_width, tex_height, stride);
  242. if (meta_texture_rectangle_check (paint_tex))
  243. priv->mask_texture = meta_texture_rectangle_new (tex_width, tex_height,
  244. COGL_PIXEL_FORMAT_A_8,
  245. COGL_PIXEL_FORMAT_A_8,
  246. stride,
  247. mask_data);
  248. else
  249. priv->mask_texture = meta_cogl_texture_new_from_data_wrapper (tex_width, tex_height,
  250. COGL_TEXTURE_NONE,
  251. COGL_PIXEL_FORMAT_A_8,
  252. COGL_PIXEL_FORMAT_ANY,
  253. stride,
  254. mask_data);
  255. g_free (mask_data);
  256. priv->mask_width = tex_width;
  257. priv->mask_height = tex_height;
  258. }
  259. }
  260. static void
  261. meta_shaped_texture_paint (ClutterActor *actor)
  262. {
  263. MetaShapedTexture *stex = (MetaShapedTexture *) actor;
  264. MetaShapedTexturePrivate *priv = stex->priv;
  265. CoglHandle paint_tex;
  266. guint tex_width, tex_height;
  267. ClutterActorBox alloc;
  268. static CoglHandle material_template = COGL_INVALID_HANDLE;
  269. static CoglHandle material_unshaped_template = COGL_INVALID_HANDLE;
  270. CoglHandle material;
  271. if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
  272. return;
  273. if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
  274. clutter_actor_realize (CLUTTER_ACTOR (stex));
  275. /* The GL EXT_texture_from_pixmap extension does allow for it to be
  276. * used together with SGIS_generate_mipmap, however this is very
  277. * rarely supported. Also, even when it is supported there
  278. * are distinct performance implications from:
  279. *
  280. * - Updating mipmaps that we don't need
  281. * - Having to reallocate pixmaps on the server into larger buffers
  282. *
  283. * So, we just unconditionally use our mipmap emulation code. If we
  284. * wanted to use SGIS_generate_mipmap, we'd have to query COGL to
  285. * see if it was supported (no API currently), and then if and only
  286. * if that was the case, set the clutter texture quality to HIGH.
  287. * Setting the texture quality to high without SGIS_generate_mipmap
  288. * support for TFP textures will result in fallbacks to XGetImage.
  289. */
  290. if (priv->create_mipmaps)
  291. paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
  292. else
  293. paint_tex = priv->texture;
  294. if (paint_tex == COGL_INVALID_HANDLE)
  295. return;
  296. tex_width = priv->tex_width;
  297. tex_height = priv->tex_height;
  298. if (tex_width == 0 || tex_height == 0) /* no contents yet */
  299. return;
  300. if (priv->shape_region == NULL)
  301. {
  302. /* No region means an unclipped shape. Use a single-layer texture. */
  303. if (priv->material_unshaped == COGL_INVALID_HANDLE)
  304. {
  305. if (G_UNLIKELY (material_unshaped_template == COGL_INVALID_HANDLE))
  306. material_unshaped_template = cogl_material_new ();
  307. priv->material_unshaped = cogl_material_copy (material_unshaped_template);
  308. }
  309. material = priv->material_unshaped;
  310. }
  311. else
  312. {
  313. meta_shaped_texture_ensure_mask (stex);
  314. if (priv->material == COGL_INVALID_HANDLE)
  315. {
  316. if (G_UNLIKELY (material_template == COGL_INVALID_HANDLE))
  317. {
  318. material_template = cogl_material_new ();
  319. cogl_material_set_layer_combine (material_template, 1,
  320. "RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
  321. NULL);
  322. }
  323. priv->material = cogl_material_copy (material_template);
  324. }
  325. material = priv->material;
  326. cogl_material_set_layer (material, 1, priv->mask_texture);
  327. }
  328. cogl_material_set_layer (material, 0, paint_tex);
  329. {
  330. CoglColor color;
  331. guchar opacity = clutter_actor_get_paint_opacity (actor);
  332. cogl_color_set_from_4ub (&color, opacity, opacity, opacity, opacity);
  333. cogl_material_set_color (material, &color);
  334. }
  335. cogl_set_source (material);
  336. clutter_actor_get_allocation_box (actor, &alloc);
  337. if (priv->clip_region)
  338. {
  339. int n_rects;
  340. int i;
  341. cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height };
  342. /* Limit to how many separate rectangles we'll draw; beyond this just
  343. * fall back and draw the whole thing */
  344. # define MAX_RECTS 16
  345. n_rects = cairo_region_num_rectangles (priv->clip_region);
  346. if (n_rects <= MAX_RECTS)
  347. {
  348. float coords[8];
  349. float x1, y1, x2, y2;
  350. for (i = 0; i < n_rects; i++)
  351. {
  352. cairo_rectangle_int_t rect;
  353. cairo_region_get_rectangle (priv->clip_region, i, &rect);
  354. if (!gdk_rectangle_intersect (&tex_rect, &rect, &rect))
  355. continue;
  356. x1 = rect.x;
  357. y1 = rect.y;
  358. x2 = rect.x + rect.width;
  359. y2 = rect.y + rect.height;
  360. coords[0] = rect.x / (alloc.x2 - alloc.x1);
  361. coords[1] = rect.y / (alloc.y2 - alloc.y1);
  362. coords[2] = (rect.x + rect.width) / (alloc.x2 - alloc.x1);
  363. coords[3] = (rect.y + rect.height) / (alloc.y2 - alloc.y1);
  364. coords[4] = coords[0];
  365. coords[5] = coords[1];
  366. coords[6] = coords[2];
  367. coords[7] = coords[3];
  368. cogl_rectangle_with_multitexture_coords (x1, y1, x2, y2,
  369. &coords[0], 8);
  370. }
  371. return;
  372. }
  373. }
  374. cogl_rectangle (0, 0,
  375. alloc.x2 - alloc.x1,
  376. alloc.y2 - alloc.y1);
  377. }
  378. static void
  379. meta_shaped_texture_pick (ClutterActor *actor,
  380. const ClutterColor *color)
  381. {
  382. MetaShapedTexture *stex = (MetaShapedTexture *) actor;
  383. MetaShapedTexturePrivate *priv = stex->priv;
  384. /* If there is no region then use the regular pick */
  385. if (priv->shape_region == NULL)
  386. CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class)
  387. ->pick (actor, color);
  388. else if (clutter_actor_should_pick_paint (actor))
  389. {
  390. CoglHandle paint_tex;
  391. ClutterActorBox alloc;
  392. guint tex_width, tex_height;
  393. paint_tex = priv->texture;
  394. if (paint_tex == COGL_INVALID_HANDLE)
  395. return;
  396. tex_width = cogl_texture_get_width (paint_tex);
  397. tex_height = cogl_texture_get_height (paint_tex);
  398. if (tex_width == 0 || tex_height == 0) /* no contents yet */
  399. return;
  400. meta_shaped_texture_ensure_mask (stex);
  401. cogl_set_source_color4ub (color->red, color->green, color->blue,
  402. color->alpha);
  403. clutter_actor_get_allocation_box (actor, &alloc);
  404. /* Paint the mask rectangle in the given color */
  405. cogl_set_source_texture (priv->mask_texture);
  406. cogl_rectangle_with_texture_coords (0, 0,
  407. alloc.x2 - alloc.x1,
  408. alloc.y2 - alloc.y1,
  409. 0, 0, 1, 1);
  410. }
  411. }
  412. static void
  413. meta_shaped_texture_get_preferred_width (ClutterActor *self,
  414. gfloat for_height,
  415. gfloat *min_width_p,
  416. gfloat *natural_width_p)
  417. {
  418. MetaShapedTexturePrivate *priv;
  419. g_return_if_fail (META_IS_SHAPED_TEXTURE (self));
  420. priv = META_SHAPED_TEXTURE (self)->priv;
  421. if (min_width_p)
  422. *min_width_p = 0;
  423. if (natural_width_p)
  424. *natural_width_p = priv->tex_width;
  425. }
  426. static void
  427. meta_shaped_texture_get_preferred_height (ClutterActor *self,
  428. gfloat for_width,
  429. gfloat *min_height_p,
  430. gfloat *natural_height_p)
  431. {
  432. MetaShapedTexturePrivate *priv;
  433. g_return_if_fail (META_IS_SHAPED_TEXTURE (self));
  434. priv = META_SHAPED_TEXTURE (self)->priv;
  435. if (min_height_p)
  436. *min_height_p = 0;
  437. if (natural_height_p)
  438. *natural_height_p = priv->tex_height;
  439. }
  440. static gboolean
  441. meta_shaped_texture_get_paint_volume (ClutterActor *self,
  442. ClutterPaintVolume *volume)
  443. {
  444. return clutter_paint_volume_set_from_allocation (volume, self);
  445. }
  446. ClutterActor *
  447. meta_shaped_texture_new (void)
  448. {
  449. ClutterActor *self = g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
  450. return self;
  451. }
  452. void
  453. meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
  454. gboolean create_mipmaps)
  455. {
  456. MetaShapedTexturePrivate *priv;
  457. g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
  458. priv = stex->priv;
  459. create_mipmaps = create_mipmaps != FALSE;
  460. if (create_mipmaps != priv->create_mipmaps)
  461. {
  462. CoglHandle base_texture;
  463. priv->create_mipmaps = create_mipmaps;
  464. base_texture = create_mipmaps ?
  465. priv->texture : COGL_INVALID_HANDLE;
  466. meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
  467. }
  468. }
  469. void
  470. meta_shaped_texture_set_shape_region (MetaShapedTexture *stex,
  471. cairo_region_t *region)
  472. {
  473. MetaShapedTexturePrivate *priv;
  474. g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
  475. priv = stex->priv;
  476. if (priv->shape_region != NULL)
  477. {
  478. cairo_region_destroy (priv->shape_region);
  479. priv->shape_region = NULL;
  480. }
  481. if (region != NULL)
  482. {
  483. cairo_region_reference (region);
  484. priv->shape_region = region;
  485. }
  486. meta_shaped_texture_dirty_mask (stex);
  487. clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
  488. }
  489. void
  490. meta_shaped_texture_update_area (MetaShapedTexture *stex,
  491. int x,
  492. int y,
  493. int width,
  494. int height)
  495. {
  496. MetaShapedTexturePrivate *priv;
  497. const cairo_rectangle_int_t clip = { x, y, width, height };
  498. priv = stex->priv;
  499. if (priv->texture == COGL_INVALID_HANDLE)
  500. return;
  501. cogl_texture_pixmap_x11_update_area (priv->texture, x, y, width, height);
  502. meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
  503. clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
  504. }
  505. static void
  506. set_cogl_texture (MetaShapedTexture *stex,
  507. CoglHandle cogl_tex)
  508. {
  509. MetaShapedTexturePrivate *priv;
  510. guint width, height;
  511. g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
  512. priv = stex->priv;
  513. if (priv->texture != COGL_INVALID_HANDLE)
  514. cogl_handle_unref (priv->texture);
  515. priv->texture = cogl_tex;
  516. if (priv->material != COGL_INVALID_HANDLE)
  517. cogl_material_set_layer (priv->material, 0, cogl_tex);
  518. if (priv->material_unshaped != COGL_INVALID_HANDLE)
  519. cogl_material_set_layer (priv->material_unshaped, 0, cogl_tex);
  520. if (cogl_tex != COGL_INVALID_HANDLE)
  521. {
  522. width = cogl_texture_get_width (cogl_tex);
  523. height = cogl_texture_get_height (cogl_tex);
  524. if (width != priv->tex_width ||
  525. height != priv->tex_height)
  526. {
  527. priv->tex_width = width;
  528. priv->tex_height = height;
  529. clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
  530. }
  531. }
  532. else
  533. {
  534. /* size changed to 0 going to an invalid handle */
  535. priv->tex_width = 0;
  536. priv->tex_height = 0;
  537. clutter_actor_queue_relayout (CLUTTER_ACTOR (stex));
  538. }
  539. clutter_actor_queue_redraw (CLUTTER_ACTOR (stex));
  540. }
  541. /**
  542. * meta_shaped_texture_set_pixmap:
  543. * @stex: The #MetaShapedTexture
  544. * @pixmap: The pixmap you want the stex to assume
  545. */
  546. void
  547. meta_shaped_texture_set_pixmap (MetaShapedTexture *stex,
  548. Pixmap pixmap)
  549. {
  550. MetaShapedTexturePrivate *priv;
  551. g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
  552. priv = stex->priv;
  553. if (priv->pixmap == pixmap)
  554. return;
  555. priv->pixmap = pixmap;
  556. if (pixmap != None)
  557. {
  558. CoglContext *ctx =
  559. clutter_backend_get_cogl_context (clutter_get_default_backend ());
  560. set_cogl_texture (stex, cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, NULL));
  561. }
  562. else
  563. set_cogl_texture (stex, COGL_INVALID_HANDLE);
  564. if (priv->create_mipmaps)
  565. meta_texture_tower_set_base_texture (priv->paint_tower, priv->texture);
  566. }
  567. /**
  568. * meta_shaped_texture_get_texture:
  569. * @stex: The #MetaShapedTexture
  570. *
  571. * Returns: (transfer none): the unshaped texture
  572. */
  573. CoglHandle
  574. meta_shaped_texture_get_texture (MetaShapedTexture *stex)
  575. {
  576. g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), COGL_INVALID_HANDLE);
  577. return stex->priv->texture;
  578. }
  579. /**
  580. * meta_shaped_texture_set_overlay_path:
  581. * @stex: a #MetaShapedTexture
  582. * @overlay_region: A region containing the parts of the mask to overlay.
  583. * All rectangles in this region are wiped clear to full transparency,
  584. * and the overlay path is clipped to this region.
  585. * @overlay_path: (transfer full): This path will be painted onto the mask
  586. * texture with a fully opaque source. Due to the lack of refcounting
  587. * in #cairo_path_t, ownership of the path is assumed.
  588. */
  589. void
  590. meta_shaped_texture_set_overlay_path (MetaShapedTexture *stex,
  591. cairo_region_t *overlay_region,
  592. cairo_path_t *overlay_path)
  593. {
  594. MetaShapedTexturePrivate *priv;
  595. g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
  596. priv = stex->priv;
  597. if (priv->overlay_region != NULL)
  598. {
  599. cairo_region_destroy (priv->overlay_region);
  600. priv->overlay_region = NULL;
  601. }
  602. if (priv->overlay_path != NULL)
  603. {
  604. cairo_path_destroy (priv->overlay_path);
  605. priv->overlay_path = NULL;
  606. }
  607. cairo_region_reference (overlay_region);
  608. priv->overlay_region = overlay_region;
  609. /* cairo_path_t does not have refcounting. */
  610. priv->overlay_path = overlay_path;
  611. meta_shaped_texture_dirty_mask (stex);
  612. }
  613. /**
  614. * meta_shaped_texture_set_clip_region:
  615. * @stex: a #MetaShapedTexture
  616. * @clip_region: (transfer full): the region of the texture that
  617. * is visible and should be painted.
  618. *
  619. * Provides a hint to the texture about what areas of the texture
  620. * are not completely obscured and thus need to be painted. This
  621. * is an optimization and is not supposed to have any effect on
  622. * the output.
  623. *
  624. * Typically a parent container will set the clip region before
  625. * painting its children, and then unset it afterwards.
  626. */
  627. void
  628. meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
  629. cairo_region_t *clip_region)
  630. {
  631. MetaShapedTexturePrivate *priv;
  632. g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
  633. priv = stex->priv;
  634. if (priv->clip_region)
  635. {
  636. cairo_region_destroy (priv->clip_region);
  637. priv->clip_region = NULL;
  638. }
  639. if (clip_region)
  640. priv->clip_region = cairo_region_copy (clip_region);
  641. else
  642. priv->clip_region = NULL;
  643. }
  644. /**
  645. * meta_shaped_texture_get_image:
  646. * @stex: A #MetaShapedTexture
  647. * @clip: A clipping rectangle, to help prevent extra processing.
  648. * In the case that the clipping rectangle is partially or fully
  649. * outside the bounds of the texture, the rectangle will be clipped.
  650. *
  651. * Flattens the two layers of the shaped texture into one ARGB32
  652. * image by alpha blending the two images, and returns the flattened
  653. * image.
  654. *
  655. * Returns: (transfer full): a new cairo surface to be freed with
  656. * cairo_surface_destroy().
  657. */
  658. cairo_surface_t *
  659. meta_shaped_texture_get_image (MetaShapedTexture *stex,
  660. cairo_rectangle_int_t *clip)
  661. {
  662. CoglHandle texture, mask_texture;
  663. cairo_rectangle_int_t texture_rect = { 0, 0, 0, 0 };
  664. cairo_surface_t *surface;
  665. g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL);
  666. texture = stex->priv->texture;
  667. if (texture == NULL)
  668. return NULL;
  669. texture_rect.width = cogl_texture_get_width (texture);
  670. texture_rect.height = cogl_texture_get_height (texture);
  671. if (clip != NULL)
  672. {
  673. /* GdkRectangle is just a typedef of cairo_rectangle_int_t,
  674. * so we can use the gdk_rectangle_* APIs on these. */
  675. if (!gdk_rectangle_intersect (&texture_rect, clip, clip))
  676. return NULL;
  677. }
  678. if (clip != NULL)
  679. texture = cogl_texture_new_from_sub_texture (texture,
  680. clip->x,
  681. clip->y,
  682. clip->width,
  683. clip->height);
  684. surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
  685. cogl_texture_get_width (texture),
  686. cogl_texture_get_height (texture));
  687. cogl_texture_get_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32,
  688. cairo_image_surface_get_stride (surface),
  689. cairo_image_surface_get_data (surface));
  690. cairo_surface_mark_dirty (surface);
  691. if (clip != NULL)
  692. cogl_object_unref (texture);
  693. mask_texture = stex->priv->mask_texture;
  694. if (mask_texture != COGL_INVALID_HANDLE)
  695. {
  696. cairo_t *cr;
  697. cairo_surface_t *mask_surface;
  698. if (clip != NULL)
  699. mask_texture = cogl_texture_new_from_sub_texture (mask_texture,
  700. clip->x,
  701. clip->y,
  702. clip->width,
  703. clip->height);
  704. mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
  705. cogl_texture_get_width (mask_texture),
  706. cogl_texture_get_height (mask_texture));
  707. cogl_texture_get_data (mask_texture, COGL_PIXEL_FORMAT_A_8,
  708. cairo_image_surface_get_stride (mask_surface),
  709. cairo_image_surface_get_data (mask_surface));
  710. cairo_surface_mark_dirty (mask_surface);
  711. cr = cairo_create (surface);
  712. cairo_set_source_surface (cr, mask_surface, 0, 0);
  713. cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN);
  714. cairo_paint (cr);
  715. cairo_destroy (cr);
  716. cairo_surface_destroy (mask_surface);
  717. if (clip != NULL)
  718. cogl_object_unref (mask_texture);
  719. }
  720. return surface;
  721. }