<commit_before>package com.rom1v.aimageview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * Generalization of the standard {@link android.widget.ImageView} component.
 * <p/>
 * It always preserves the aspect-ratio, and generalizes the {@link android.widget
 * .ImageView.ScaleType scaleType} mechanism by using 4 parameters:
 * <ul>
 * <li><code>xWeight</code> and <code>yWeight</code> indicating where the crop or margins must be
 * applied.</li>
 * <li><code>scale</code> for enabling/disabling downscaling and/or upscaling</li>
 * <li><code>fit</code> for choosing if the aspect-ratio must be respecting by adding margins
 * (displaying the whole image) or by cropping (filling the component)</li>
 * </ul>
 * <p/>
 * See {@link com.rom1v.aimageview.R.styleable#AImageView AImageView attributes}.
 *
 * @attr ref R.styleable#AImageView_xWeight
 * @attr ref R.styleable#AImageView_yWeight
 * @attr ref R.styleable#AImageView_scale
 * @attr ref R.styleable#AImageView_fit
 */
public class AImageView extends ImageView {

    /**
     * Fit type, defining how to fit the image to the container.
     */
    public enum Fit {

        /** Fit the image inside (add margins to display the whole image content). */
        INSIDE,

        /** Fit the image outside (crop the image to fill the component). */
        OUTSIDE,

        /** Fit the image horizontally */
        HORIZONTAL,

        /** Fit the image vertically */
        VERTICAL;

        /**
         * Convert the attr value to a typed {@link Fit} value.
         *
         * @param attrValue value defined in <code>attrs.xml</code>.
         * @return the associated {@link Fit} instance
         * @throws java.lang.IllegalArgumentException if the value is unknown
         */
        private static Fit fromAttrValue(int attrValue) {
            switch (attrValue) {
                case 0:
                    return INSIDE;
                case 1:
                    return OUTSIDE;
                case 2:
                    return HORIZONTAL;
                case 3:
                    return VERTICAL;
                default:
                    throw new IllegalArgumentException();
            }
        }
    }

    /** Flag indicating that downscaling is acceptable. */
    public static final int DOWNSCALE = 1 << 0;

    /** Flag indicating that upscaling is acceptable. */
    public static final int UPSCALE = 1 << 1;

    /** x weight (in [0;1]). */
    private float xWeight;

    /** y weight (in [0;1]). */
    private float yWeight;

    /** Scale flags (bitwise of {@link #DOWNSCALE} and {@link #UPSCALE}). */
    private int scaleFlags;

    /** Fit type. */
    private Fit fit;

    public AImageView(Context context) {
        super(context);
        forceMatrixScaleType();
    }

    public AImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
        forceMatrixScaleType();
    }

    public AImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
        forceMatrixScaleType();
    }

    private void forceMatrixScaleType() {
        // this component works only with scaleType MATRIX
        setScaleType(ScaleType.MATRIX);
    }

    private void init(Context context, AttributeSet attrs) {
        // load values from XML attributes
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
                R.styleable.AImageView, 0, 0);
        try {
            setXWeight(a.getFloat(R.styleable.AImageView_xWeight, .5f));
            setYWeight(a.getFloat(R.styleable.AImageView_yWeight, .5f));

            int fitInt = a.getInt(R.styleable.AImageView_fit, 0);
            setFit(Fit.fromAttrValue(fitInt));

            setScaleFlags(a.getInt(R.styleable.AImageView_scale, UPSCALE | DOWNSCALE));
        } finally {
            a.recycle();
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        if (getScaleType() != ScaleType.MATRIX) {
            // use the default ImageView behavior
            return;
        }
        Drawable drawable = getDrawable();
        if (drawable == null) {
            // nothing to draw
            return;
        }

        int w = right - left - getPaddingLeft() - getPaddingRight();
        int h = bottom - top - getPaddingTop() - getPaddingBottom();
        int imageWidth = drawable.getIntrinsicWidth();
        int imageHeight = drawable.getIntrinsicHeight();

        // static method for easier testing
        Matrix matrix = getTransformMatrix(w, h, imageWidth, imageHeight, xWeight, yWeight, fit,
                scaleFlags);
        setImageMatrix(matrix);
    }

    static Matrix getTransformMatrix(int w, int h, int imageWidth, int imageHeight, float xWeight,
                                     float yWeight, Fit fit, int scaleFlags) {
        Matrix matrix = new Matrix();

        float scale;
        if (scaleFlags == 0) {
            // do not scale
            scale = 1;
        } else {
            // the image has a greater aspect-ratio than the container ?
            boolean imageHasGreaterAR = imageWidth * h > imageHeight * w;
            if (fit == Fit.HORIZONTAL || imageHasGreaterAR && fit == Fit.INSIDE ||
                    !imageHasGreaterAR && fit == Fit.OUTSIDE) {
                // fit the width
                scale = (float) w / imageWidth;
            } else {
                // fit == Fit.VERTICAL || !imageHasGreaterAR && fit == Fit.INSIDE ||
                // imageHasGraterAR && fit == Fit.OUTSIDE

                // fit the height
                scale = (float) h / imageHeight;
            }
            if (scale > 1f && (scaleFlags & UPSCALE) == 0 || scale < 1f && (scaleFlags &
                    DOWNSCALE) == 0) {
                // respect scaling constraints
                scale = 1;
            }
        }

        // resize proportionally
        matrix.setScale(scale, scale);

        // translate according to weights
        float tx = xWeight * (w - imageWidth * scale);
        float ty = yWeight * (h - imageHeight * scale);
        matrix.postTranslate(tx, ty);<commit_msg>Prevent negative image scaling<commit_after>package com.rom1v.aimageview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Matrix;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * Generalization of the standard {@link android.widget.ImageView} component.
 * <p/>
 * It always preserves the aspect-ratio, and generalizes the {@link android.widget
 * .ImageView.ScaleType scaleType} mechanism by using 4 parameters:
 * <ul>
 * <li><code>xWeight</code> and <code>yWeight</code> indicating where the crop or margins must be
 * applied.</li>
 * <li><code>scale</code> for enabling/disabling downscaling and/or upscaling</li>
 * <li><code>fit</code> for choosing if the aspect-ratio must be respecting by adding margins
 * (displaying the whole image) or by cropping (filling the component)</li>
 * </ul>
 * <p/>
 * See {@link com.rom1v.aimageview.R.styleable#AImageView AImageView attributes}.
 *
 * @attr ref R.styleable#AImageView_xWeight
 * @attr ref R.styleable#AImageView_yWeight
 * @attr ref R.styleable#AImageView_scale
 * @attr ref R.styleable#AImageView_fit
 */
public class AImageView extends ImageView {

    /**
     * Fit type, defining how to fit the image to the container.
     */
    public enum Fit {

        /** Fit the image inside (add margins to display the whole image content). */
        INSIDE,

        /** Fit the image outside (crop the image to fill the component). */
        OUTSIDE,

        /** Fit the image horizontally */
        HORIZONTAL,

        /** Fit the image vertically */
        VERTICAL;

        /**
         * Convert the attr value to a typed {@link Fit} value.
         *
         * @param attrValue value defined in <code>attrs.xml</code>.
         * @return the associated {@link Fit} instance
         * @throws java.lang.IllegalArgumentException if the value is unknown
         */
        private static Fit fromAttrValue(int attrValue) {
            switch (attrValue) {
                case 0:
                    return INSIDE;
                case 1:
                    return OUTSIDE;
                case 2:
                    return HORIZONTAL;
                case 3:
                    return VERTICAL;
                default:
                    throw new IllegalArgumentException();
            }
        }
    }

    /** Flag indicating that downscaling is acceptable. */
    public static final int DOWNSCALE = 1 << 0;

    /** Flag indicating that upscaling is acceptable. */
    public static final int UPSCALE = 1 << 1;

    /** x weight (in [0;1]). */
    private float xWeight;

    /** y weight (in [0;1]). */
    private float yWeight;

    /** Scale flags (bitwise of {@link #DOWNSCALE} and {@link #UPSCALE}). */
    private int scaleFlags;

    /** Fit type. */
    private Fit fit;

    public AImageView(Context context) {
        super(context);
        forceMatrixScaleType();
    }

    public AImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
        forceMatrixScaleType();
    }

    public AImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
        forceMatrixScaleType();
    }

    private void forceMatrixScaleType() {
        // this component works only with scaleType MATRIX
        setScaleType(ScaleType.MATRIX);
    }

    private void init(Context context, AttributeSet attrs) {
        // load values from XML attributes
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
                R.styleable.AImageView, 0, 0);
        try {
            setXWeight(a.getFloat(R.styleable.AImageView_xWeight, .5f));
            setYWeight(a.getFloat(R.styleable.AImageView_yWeight, .5f));

            int fitInt = a.getInt(R.styleable.AImageView_fit, 0);
            setFit(Fit.fromAttrValue(fitInt));

            setScaleFlags(a.getInt(R.styleable.AImageView_scale, UPSCALE | DOWNSCALE));
        } finally {
            a.recycle();
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        if (getScaleType() != ScaleType.MATRIX) {
            // use the default ImageView behavior
            return;
        }
        Drawable drawable = getDrawable();
        if (drawable == null) {
            // nothing to draw
            return;
        }

        int w = right - left - getPaddingLeft() - getPaddingRight();
        int h = bottom - top - getPaddingTop() - getPaddingBottom();
        int imageWidth = drawable.getIntrinsicWidth();
        int imageHeight = drawable.getIntrinsicHeight();

        // static method for easier testing
        Matrix matrix = getTransformMatrix(w, h, imageWidth, imageHeight, xWeight, yWeight, fit,
                scaleFlags);
        setImageMatrix(matrix);
    }

    static Matrix getTransformMatrix(int w, int h, int imageWidth, int imageHeight, float xWeight,
                                     float yWeight, Fit fit, int scaleFlags) {
        Matrix matrix = new Matrix();

        float scale;
        if (scaleFlags == 0) {
            // do not scale
            scale = 1;
        } else {
            // the image has a greater aspect-ratio than the container ?
            boolean imageHasGreaterAR = imageWidth * h > imageHeight * w;
            if (fit == Fit.HORIZONTAL || imageHasGreaterAR && fit == Fit.INSIDE ||
                    !imageHasGreaterAR && fit == Fit.OUTSIDE) {
                // fit the width
                scale = (float) w / imageWidth;
            } else {
                // fit == Fit.VERTICAL || !imageHasGreaterAR && fit == Fit.INSIDE ||
                // imageHasGraterAR && fit == Fit.OUTSIDE

                // fit the height
                scale = (float) h / imageHeight;
            }
            if (scale > 1f && (scaleFlags & UPSCALE) == 0 || scale < 1f && (scaleFlags &
                    DOWNSCALE) == 0) {
                // respect scaling constraints
                scale = 1;
            } else if (scale < 0) {
                // may happen when w or h is negative, i.e. when the padding is greater than
                // the component; in that case, we do not want to reverse the image
                scale = 0;
            }
        }

        // resize proportionally
        matrix.setScale(scale, scale);

        // translate according to weights
        float tx = xWeight * (w - imageWidth * scale);
        float ty = yWeight * (h - imageHeight * scale);
        matrix.postTranslate(tx, ty);
{'fraction_non_alphanumeric': 0.10117557830868411, 'fraction_numerical': 0.004247250663632916, 'mean_word_length': 1.9913793103448276, 'pattern_counts': {'":': 0, '<': 54, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1084963', 'n_tokens_mistral': 3731, 'n_tokens_neox': 3475, 'n_words': 1088}