manually calculate text width/height instead of relying on getBBox()