<commit_before>package org.osmdroid.views.overlay;

import org.osmdroid.ResourceProxy;
import org.osmdroid.views.MapView;
import org.osmdroid.views.safecanvas.ISafeCanvas;
import org.osmdroid.views.safecanvas.SafeTranslatedCanvas;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Build;

/**
 * An overlay class that uses the safe drawing canvas to draw itself and can be zoomed in to high
 * levels without drawing issues.
 * 
 * @see {@link ISafeCanvas}
 */
public abstract class SafeDrawOverlay extends Overlay {

	private static final SafeTranslatedCanvas sSafeCanvas = new SafeTranslatedCanvas();
	private static final Matrix sMatrix = new Matrix();
	private static final float[] sMatrixValues = new float[9];
	private boolean mUseSafeCanvas = true;

	protected abstract void drawSafe(final ISafeCanvas c, final MapView osmv, final boolean shadow);

	public SafeDrawOverlay(Context ctx) {
		super(ctx);
	}

	public SafeDrawOverlay(ResourceProxy pResourceProxy) {
		super(pResourceProxy);
	}

	protected void draw(final Canvas c, final MapView osmv, final boolean shadow) {

		sSafeCanvas.setCanvas(c);

		if (this.isUsingSafeCanvas()) {

			// Find the screen offset
			Rect screenRect = osmv.getProjection().getScreenRect();
			sSafeCanvas.xOffset = -screenRect.left;
			sSafeCanvas.yOffset = -screenRect.top;

			// Save the canvas state
			c.save();

			// Translate the coordinates
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
				final float scaleX = osmv.getScaleX();
				final float scaleY = osmv.getScaleY();
				c.translate(screenRect.left * scaleX, screenRect.top * scaleY);
			} else {
				c.getMatrix(sMatrix);
				sMatrix.preTranslate(screenRect.left, screenRect.top);
				c.setMatrix(sMatrix);
			}
		} else {
			sSafeCanvas.xOffset = 0;
			sSafeCanvas.yOffset = 0;
		}
		this.drawSafe(sSafeCanvas, osmv, shadow);

		if (this.isUsingSafeCanvas()) {
			c.restore();
		}
	}

	public boolean isUsingSafeCanvas() {
		return mUseSafeCanvas;
	}

	public void setUseSafeCanvas(boolean useSafeCanvas) {
		mUseSafeCanvas = useSafeCanvas;
	}
}
<commit_msg>Fixes safe canvas issues introduced in r1153. When zoomed in to a high zoom level, scrolling appears to "shake" the screen by a pixel or two. Since translate() still takes float values, the scroll value is subject to rounding errors. To counteract that, we will calculate the rounding error when converting from float to int and adjust as necessary.<commit_after>package org.osmdroid.views.overlay;

import org.osmdroid.ResourceProxy;
import org.osmdroid.views.MapView;
import org.osmdroid.views.safecanvas.ISafeCanvas;
import org.osmdroid.views.safecanvas.SafeTranslatedCanvas;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Build;

/**
 * An overlay class that uses the safe drawing canvas to draw itself and can be zoomed in to high
 * levels without drawing issues.
 * 
 * @see {@link ISafeCanvas}
 */
public abstract class SafeDrawOverlay extends Overlay {

	private static final SafeTranslatedCanvas sSafeCanvas = new SafeTranslatedCanvas();
	private static final Matrix sMatrix = new Matrix();
	private static final float[] sMatrixValues = new float[9];
	private boolean mUseSafeCanvas = true;

	protected abstract void drawSafe(final ISafeCanvas c, final MapView osmv, final boolean shadow);

	public SafeDrawOverlay(Context ctx) {
		super(ctx);
	}

	public SafeDrawOverlay(ResourceProxy pResourceProxy) {
		super(pResourceProxy);
	}

	protected void draw(final Canvas c, final MapView osmv, final boolean shadow) {

		sSafeCanvas.setCanvas(c);

		if (this.isUsingSafeCanvas()) {

			// Find the screen offset
			Rect screenRect = osmv.getProjection().getScreenRect();
			sSafeCanvas.xOffset = -screenRect.left;
			sSafeCanvas.yOffset = -screenRect.top;

			// Save the canvas state
			c.save();

			// Since the translate calls still take a float, there can be rounding errors
			// Let's calculate the error, and adjust for it.
			final int floatErrorX = screenRect.left - (int) (float) screenRect.left;
			final int floatErrorY = screenRect.top - (int) (float) screenRect.top;

			// Translate the coordinates
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
				final float scaleX = osmv.getScaleX();
				final float scaleY = osmv.getScaleY();
				c.translate(screenRect.left * scaleX, screenRect.top * scaleY);
				c.translate(floatErrorX, floatErrorY);
			} else {
				c.getMatrix(sMatrix);
				sMatrix.preTranslate(screenRect.left, screenRect.top);
				sMatrix.preTranslate(floatErrorX, floatErrorY);
				c.setMatrix(sMatrix);
			}
		} else {
			sSafeCanvas.xOffset = 0;
			sSafeCanvas.yOffset = 0;
		}
		this.drawSafe(sSafeCanvas, osmv, shadow);

		if (this.isUsingSafeCanvas()) {
			c.restore();
		}
	}

	public boolean isUsingSafeCanvas() {
		return mUseSafeCanvas;
	}

	public void setUseSafeCanvas(boolean useSafeCanvas) {
		mUseSafeCanvas = useSafeCanvas;
	}
}

{'fraction_non_alphanumeric': 0.09175887066005342, 'fraction_numerical': 0.0019076688286913392, 'mean_word_length': 3.693822739480752, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4639084', 'n_tokens_mistral': 1768, 'n_tokens_neox': 1556, 'n_words': 441}