line-width-scale.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Copyright © 2006 Red Hat, Inc.
  3. *
  4. * Permission to use, copy, modify, distribute, and sell this software
  5. * and its documentation for any purpose is hereby granted without
  6. * fee, provided that the above copyright notice appear in all copies
  7. * and that both that copyright notice and this permission notice
  8. * appear in supporting documentation, and that the name of
  9. * Red Hat, Inc. not be used in advertising or publicity pertaining to
  10. * distribution of the software without specific, written prior
  11. * permission. Red Hat, Inc. makes no representations about the
  12. * suitability of this software for any purpose. It is provided "as
  13. * is" without express or implied warranty.
  14. *
  15. * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  16. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
  18. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  19. * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
  21. * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22. *
  23. * Author: Carl D. Worth <cworth@cworth.org>
  24. */
  25. #include "cairo-test.h"
  26. /* This test exercises the various interactions between
  27. * cairo_set_line_width and cairo_scale. Specifically it shows how
  28. * separate transformations can affect the pen for stroking compared
  29. * to the path itself.
  30. *
  31. * This was inspired by an image by Maxim Shemanarev demonstrating the
  32. * flexible-pipeline nature of his Antigrain Geometry project:
  33. *
  34. * http://antigrain.com/tips/line_alignment/conv_order.gif
  35. *
  36. * It also uncovered some behavior in cairo that I found surprising.
  37. * Namely, cairo_set_line_width was not transforming the width
  38. * according the the current CTM, but instead delaying that
  39. * transformation until the time of cairo_stroke.
  40. *
  41. * This delayed behavior was released in cairo 1.0 so we're going to
  42. * document this as the way cairo_set_line_width works rather than
  43. * considering this a bug.
  44. */
  45. #define LINE_WIDTH 13
  46. #define SPLINE 50.0
  47. #define XSCALE 0.5
  48. #define YSCALE 2.0
  49. #define WIDTH (XSCALE * SPLINE * 6.0)
  50. #define HEIGHT (YSCALE * SPLINE * 2.0)
  51. static void
  52. spline_path (cairo_t *cr)
  53. {
  54. cairo_save (cr);
  55. {
  56. cairo_move_to (cr,
  57. - SPLINE, 0);
  58. cairo_curve_to (cr,
  59. - SPLINE / 4, - SPLINE,
  60. SPLINE / 4, SPLINE,
  61. SPLINE, 0);
  62. }
  63. cairo_restore (cr);
  64. }
  65. /* If we scale before setting the line width or creating the path,
  66. * then obviously both will be scaled. */
  67. static void
  68. scale_then_set_line_width_and_stroke (cairo_t *cr)
  69. {
  70. cairo_scale (cr, XSCALE, YSCALE);
  71. cairo_set_line_width (cr, LINE_WIDTH);
  72. spline_path (cr);
  73. cairo_stroke (cr);
  74. }
  75. /* This is used to verify the results of
  76. * scale_then_set_line_width_and_stroke.
  77. *
  78. * It uses save/restore pairs to isolate the scaling of the path and
  79. * line_width and ensures that both are scaled.
  80. */
  81. static void
  82. scale_path_and_line_width (cairo_t *cr)
  83. {
  84. cairo_save (cr);
  85. {
  86. cairo_scale (cr, XSCALE, YSCALE);
  87. spline_path (cr);
  88. }
  89. cairo_restore (cr);
  90. cairo_save (cr);
  91. {
  92. cairo_scale (cr, XSCALE, YSCALE);
  93. cairo_set_line_width (cr, LINE_WIDTH);
  94. cairo_stroke (cr);
  95. }
  96. cairo_restore (cr);
  97. }
  98. /* This is the case that was surprising.
  99. *
  100. * Setting the line width before scaling doesn't change anything. The
  101. * line width will be interpreted under the CTM in effect at the time
  102. * of cairo_stroke, so the line width will be scaled as well as the
  103. * path here.
  104. */
  105. static void
  106. set_line_width_then_scale_and_stroke (cairo_t *cr)
  107. {
  108. cairo_set_line_width (cr, LINE_WIDTH);
  109. cairo_scale (cr, XSCALE, YSCALE);
  110. spline_path (cr);
  111. cairo_stroke (cr);
  112. }
  113. /* Here then is the way to achieve the alternate result.
  114. *
  115. * This uses save/restore pairs to isolate the scaling of the path and
  116. * line_width and ensures that the path is scaled while the line width
  117. * is not.
  118. */
  119. static void
  120. scale_path_not_line_width (cairo_t *cr)
  121. {
  122. cairo_save (cr);
  123. {
  124. cairo_scale (cr, XSCALE, YSCALE);
  125. spline_path (cr);
  126. }
  127. cairo_restore (cr);
  128. cairo_save (cr);
  129. {
  130. cairo_set_line_width (cr, LINE_WIDTH);
  131. cairo_stroke (cr);
  132. }
  133. cairo_restore (cr);
  134. }
  135. static cairo_test_status_t
  136. draw (cairo_t *cr, int width, int height)
  137. {
  138. int i;
  139. void (* const figures[4]) (cairo_t *cr) = {
  140. scale_then_set_line_width_and_stroke,
  141. scale_path_and_line_width,
  142. set_line_width_then_scale_and_stroke,
  143. scale_path_not_line_width
  144. };
  145. cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
  146. cairo_paint (cr);
  147. cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
  148. for (i = 0; i < 4; i++) {
  149. cairo_save (cr);
  150. cairo_translate (cr,
  151. WIDTH/4 + (i % 2) * WIDTH/2,
  152. HEIGHT/4 + (i / 2) * HEIGHT/2);
  153. (figures[i]) (cr);
  154. cairo_restore (cr);
  155. }
  156. return CAIRO_TEST_SUCCESS;
  157. }
  158. CAIRO_TEST (line_width_scale,
  159. "Tests interaction of cairo_set_line_width with cairo_scale",
  160. "stroke", /* keywords */
  161. NULL, /* requirements */
  162. WIDTH, HEIGHT,
  163. NULL, draw)