Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Bug in AndroidCanvas.fillRoundRect ?

7 views
Skip to first unread message

Guillermo Rodriguez Garcia

unread,
Nov 19, 2020, 4:19:45 AM11/19/20
to PlayN
Hello there,

It looks like there's something wrong with AndroidCanvas.fillRoundRect(). I am trying to fill some rectangles using a linear gradient. This is how it should like:

fixed.png

This is how it currently looks like in Android:

original.png

The problem is that the origin for the gradient fill is reset to the origin of each shape (see the rectangle in the bottom right).

This happens only for fillRoundRect; fillRect is not affected.

I have been looking into this and I think I know where the problem is. The current implementation of AndroidCanvas.fillRoundRect looks like this:

public Canvas fillRoundRect(float x, float y, float width, float height, float radius) {
    this.canvas.translate(x, y);
    rectf.set(0.0F, 0.0F, width, height);
    this.canvas.drawRoundRect(rectf, radius, radius, this.currentState().prepareFill());
    this.canvas.translate(-x, -y);
    this.isDirty = true;
    return this;
}

The problem is due to the canvas.translate calls.

This fixes the issue:

public Canvas fillRoundRect(float x, float y, float width, float height, float radius) {
  rectf.set(x, y, x + width, y + height);
  canvas.drawRoundRect(rectf, radius, radius, currentState().prepareFill());
  dirty = true;
  return this;
}

To me this seems more natural, so I was curious about why the translate calls were used in the first place. Going through the commit logs I found this one:

===
From ab72fb60845312a2cb2815874f1ad995d89d90f0 Mon Sep 17 00:00:00 2001
From: Michael Bayne <x...@xxx.com>
Date: Wed, 16 May 2012 15:31:15 -0700
Subject: [PATCH] Work around odd Android Canvas drawRoundRect bug.

If the rect supplied to drawRoundRect has non-zero x or y, it causes the round rectangle to be incorrectly rendered. So we simply translate the canvas, draw using a rect at (0, 0) and then translate it back.

Surely someone would have discovered this bug already? Round rects are all the rage in UIs.
[...]
===

The thing is that the original code (before this commit) looked like this:

  rectf.set(x, y, width, height);
  canvas.drawRoundRect(rectf, radius, radius, currentState().prepareFill());

but this was wrong -- rectf should be set to (x, y, x + width, y + height) (the last two parameters are not w/h, but the right and bottom coordinates). Probably this is why it was not working as expected if x or y were not 0.
 
So I am going to prepare a PR to "fix the fix".

Another option would be to use the drawRoundRect method that takes (x, y, width, height) instead of a Rect, and avoid the creation of an intermediate Rect. However this was introduced in API level 21 which doesn't work if building PlayN using Maven (android.version is currently set to 4.1.1.4, which is the latest version available in Maven central).

PR will follow shortly.

Thank you,

Guillermo

Guillermo Rodriguez Garcia

unread,
Nov 19, 2020, 5:22:06 AM11/19/20
to PlayN
Reply all
Reply to author
Forward
0 new messages