diff options
author | fvogel <fvogelnew1@free.fr> | 2017-09-16 08:26:38 (GMT) |
---|---|---|
committer | fvogel <fvogelnew1@free.fr> | 2017-09-16 08:26:38 (GMT) |
commit | 28ecd1d8e1c3f719e76cf10280c207b62dcd3769 (patch) | |
tree | 4f94d2704659fb5c378b3792edb54a4db371a885 | |
parent | 7cf5207818e3ecc3b7a6a03bcafafb755f693297 (diff) | |
parent | aa02ff624c358037f14b1716057349f06634f5d1 (diff) | |
download | tk-28ecd1d8e1c3f719e76cf10280c207b62dcd3769.zip tk-28ecd1d8e1c3f719e76cf10280c207b62dcd3769.tar.gz tk-28ecd1d8e1c3f719e76cf10280c207b62dcd3769.tar.bz2 |
Fix [3406785]: Incorrect coords rounding, pixel jump in drawing canvas items.
-rw-r--r-- | generic/tkRectOval.c | 102 |
1 files changed, 97 insertions, 5 deletions
diff --git a/generic/tkRectOval.c b/generic/tkRectOval.c index 50b5f1a..4d48fe7 100644 --- a/generic/tkRectOval.c +++ b/generic/tkRectOval.c @@ -759,11 +759,103 @@ DisplayRectOval( &x1, &y1); Tk_CanvasDrawableCoords(canvas, rectOvalPtr->bbox[2],rectOvalPtr->bbox[3], &x2, &y2); - if (x2 <= x1) { - x2 = x1+1; - } - if (y2 <= y1) { - y2 = y1+1; + if (x2 == x1) { + + /* + * The width of the bounding box corresponds to less than one pixel + * on screen. Adjustment is needed to avoid drawing attempts with zero + * width items (which would draw nothing). The bounding box spans + * either 1 or 2 pixels. Select which pixel will be drawn. + */ + + short ix1 = (short) (rectOvalPtr->bbox[0]); + short ix2 = (short) (rectOvalPtr->bbox[2]); + + if (ix1 == ix2) { + + /* + * x1 and x2 are "within the same pixel". Use this pixel. + * Note: the degenerated case (bbox[0]==bbox[2]) of a completely + * flat box results in arbitrary selection of the pixel at the + * right (with positive coordinate) or left (with negative + * coordinate) of the box. There is no "best choice" here. + */ + + if (ix1 > 0) { + x2 += 1; + } else { + x1 -= 1; + } + } else { + + /* + * (x1,x2) span two pixels. Select the one with the larger + * covered "area". + */ + + if (ix1 > 0) { + if ((rectOvalPtr->bbox[2] - ix2) > (ix2 - rectOvalPtr->bbox[0])) { + x2 += 1; + } else { + x1 -= 1; + } + } else { + if ((rectOvalPtr->bbox[2] - ix1) > (ix1 - rectOvalPtr->bbox[0])) { + x2 += 1; + } else { + x1 -= 1; + } + } + } + } + if (y2 == y1) { + + /* + * The height of the bounding box corresponds to less than one pixel + * on screen. Adjustment is needed to avoid drawing attempts with zero + * height items (which would draw nothing). The bounding box spans + * either 1 or 2 pixels. Select which pixel will be drawn. + */ + + short iy1 = (short) (rectOvalPtr->bbox[1]); + short iy2 = (short) (rectOvalPtr->bbox[3]); + + if (iy1 == iy2) { + + /* + * y1 and y2 are "within the same pixel". Use this pixel. + * Note: the degenerated case (bbox[1]==bbox[3]) of a completely + * flat box results in arbitrary selection of the pixel below + * (with positive coordinate) or above (with negative coordinate) + * the box. There is no "best choice" here. + */ + + if (iy1 > 0) { + y2 += 1; + } else { + y1 -= 1; + } + } else { + + /* + * (y1,y2) span two pixels. Select the one with the larger + * covered "area". + */ + + if (iy1 > 0) { + if ((rectOvalPtr->bbox[3] - iy2) > (iy2 - rectOvalPtr->bbox[1])) { + y2 += 1; + } else { + y1 -= 1; + } + } else { + if ((rectOvalPtr->bbox[3] - iy1) > (iy1 - rectOvalPtr->bbox[1])) { + y2 += 1; + } else { + y1 -= 1; + } + } + } } /* |