/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <math.h>
#include "jni_util.h"
#include "GraphicsPrimitiveMgr.h"
#include "Region.h"
#include "sun_java2d_loops_ScaledBlit.h"
/*
* The scaling loops used inside the helper functions are based on the
* following pseudocode for stepping through the source image:
*
* shift - number of bits of sub-pixel precision in scaled values
* srcxorig, srcyorig - scaled location of first pixel
* srcxinc, srcyinc - scaled x and y increments
* dstwidth, dstheight - number of pixels to process across and down
*
* 1. srcy = srcyorig;
* 2. for (dstheight) {
* 3. srcx = srcxorig;
* 4. for (dstwidth) {
* 5. fetch and process pixel for (srcx >> shift, srcy >> shift)
* 6. srcx += srcxinc;
* 7. }
* 8. srcy += srcyinc;
* 9. }
*
* Note that each execution of line 6 or 8 accumulates error of
* +/- 1 into the scaled coordinate variables. These lines are
* each executed once per pixel across or once per pixel down
* the region being iterated over, thus the error can accumulate
* up to a magnitude of dstwidth in the horizontal direction and
* dstheight in the vertical direction.
*
* If the error ever reaches a magnitude of (1 << shift) then we
* will be off by at least 1 source pixel in our mapping.
*
* Note that we increment the source coordinates by the srcxinc
* and srcyinc variables in each step. Thus, if our error ever
* accumulates to a magnitude equal to srcxinc or srcyinc then
* we will be ahead or behind of "where we should be" by at least
* one iteration. Since each iteration is a destination pixel,
* this means that our actual location will be off by at least
* one destination pixel.
*
* This means that all of the values:
*
* - (1 << shift)
* - srcxinc
* - srcyinc
*
* all represent a maximum bound on how much error we can accumulate
* before we are off by a source or a destination pixel. Thus,
* we should make sure that we never process more than that many
* pixels if we want to maintain single pixel accuracy. Even
* better would be to process many fewer pixels than those bounds
* to ensure that our accumulated error is much smaller than a
* pixel.
*/
/*
* Find and return the largest tile size that is a power of 2 and
* which is small enough to yield some reassuring degree of subpixel
* accuracy. The degree of subpixel accuracy that will be preserved
* by the tile size it chooses will vary and the details on how
* it makes this decision are detailed in the comments below.
*/
static jint
{
/*
* The initial value of shift is our first estimate for
* the power of 2 for our tilesize since it ensures
* less than 1 source pixel of error.
*
* Reducing it until (1 << shift) is not larger than the
* smallest of our increments ensures we will have no more
* than 1 destination pixel of error as well.
*/
}
if (sxinc == 0) {
/* Degenerate case will cause infinite loop in next loop... */
return 1;
}
shift--;
}
/*
* shift is now the largest it can be for less than 1 pixel
* of error in either source or destination spaces.
*
* Now we will try for at least 8 bits of subpixel accuracy
* with a tile size of at least 256x256 and reduce our subpixel
* accuracy on a sliding scale down to a tilesize of 1x1 when
* we have no bits of sub-pixel accuracy.
*/
if (shift >= 16) {
/* Subtracting 8 asks for 8 bits of subpixel accuracy. */
shift -= 8;
} else {
/* Ask for half of the remaining bits to be subpixel accuracy. */
/* Rounding is in favor of subpixel accuracy over tile size. */
/* Worst case, shift == 0 and tilesize == (1 << 0) == 1 */
shift /= 2;
}
return (1 << shift);
}
/*
* For a given integer destination pixel coordinate "id", calculate the
* integer destination coordinate of the start of the "ts" sized tile
* in which it resides.
* Tiles all start at even multiples of the tile size from the integer
* destination origin "io".
*
* id == integer destination coordinate
* io == integer destination operation origin
* ts == tilesize (must be power of 2)
*/
/*
* For a given integer destination pixel coordinate "id", calculate the
* sub-pixel accurate source coordinate from which its sample comes.
* The returned source coordinate is expressed in a shifted fractional
* arithmetic number system.
*
* id == integer destination coordinate
* fo == floating point destination operation origin,
* sf == source coordinate scale factor per destination pixel
* (multiplied by fractional arithmetic "shift")
*
* The caller is required to cast this value to the appropriate
* integer type for the needed precision. The rendering code which
* deals only with valid coordinates within the bounds of the source
* rectangle uses jint. The setup code, which occasionally deals
* with coordinates that run out of bounds, uses jlong.
*
* Note that the rounding in this calculation is at a fraction of a
* source pixel of (1.0 / (1<<shift)) since the scale factor includes
* the fractional shift. As a result, the type of rounding used is
* not very significant (floor, floor(x+.5), or ceil(x-.5)), but the
* ceil(x-.5) version is used for consistency with the way that pixel
* coordinates are rounded to assign the ".5" value to the lower
* integer.
*/
/*
* Reverse map a srctarget coordinate into device space and refine the
* answer. More specifically, what we are looking for is the smallest
* destination coordinate that maps to a source coordinate that is
* greater than or equal to the given target source coordinate.
*
* Note that since the inner loops use math that maps a destination
* coordinate into source space and that, even though the equation
* we use below is the theoretical inverse of the dst->src mapping,
* we cannot rely on floating point math to guarantee that applying
* both of these equations in sequence will give us an exact mapping
* of src->dst->src. Thus, we must search back and forth to see if
* we really map back to the given source coordinate and that we are
* the smallest destination coordinate that does so.
*
* Note that, in practice, the answer from the initial guess tends to
* be the right answer most of the time and the loop ends up finding
* one iteration to be ">= srctarget" and the next to be "< srctarget"
* and thus finds the answer in 2 iterations. A small number of
* times, the initial guess is 1 too low and so we do one iteration
* at "< srctarget" and the next at ">= srctarget" and again find the
* answer in 2 iterations. All cases encountered during testing ended
* up falling into one of those 2 categories and so the loop was always
* executed exactly twice.
*
* Note also that the calculation of srcloc below may attempt to calculate
* the src location of the destination pixel which is "1 beyond" the
* end of the source image. Since our shift calculation code in the
* main function only guaranteed that "srcw << shift" did not overflow
* a 32-bit signed integer, we cannot guarantee that "(srcw+1) << shift"
* or, more generally, "(srcw << shift)+srcinc" does not overflow.
* As a result, we perform our calculations here with jlong values
* so that we aren't affected by this overflow. Since srcw (shifted)
* and srcinc are both 32-bit values, their sum cannot possibly overflow
* a jlong. In fact, we can step up to a couple of billion steps of
* size "srcinc" past the end of the image before we have to worry
* about overflow - in practice, though, the search never steps more
* than 1 past the end of the image so this buffer is more than enough.
*/
static jint
{
/* Make a first estimate of dest coordinate from srctarget */
/* Loop until we get at least one value < and one >= the target */
while (JNI_TRUE) {
/*
* Find src coordinate from dest coordinate using the same
* math we will use below when iterating over tiles.
*/
}
if (lsrcloc >= lsrctarget) {
/*
* If we were previously less than target, then the current
* dstloc is the smallest dst which maps >= the target.
*/
if (wasneg) break;
dstloc--;
} else {
/*
* If we were previously greater than target, then this must
* be the first dstloc which maps to < the target. Since we
* want the smallest which maps >= the target, increment it
* first before returning.
*/
dstloc++;
if (waspos) break;
}
}
return dstloc;
}
/*
* Class: sun_java2d_loops_ScaledBlit
* Method: Scale
* Signature: (Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;Ljava/awt/Composite;Lsun/java2d/pipe/Region;IIIIDDDD)V
*/
{
return;
}
}
return;
}
return;
}
/*
* Determine the precision to use for the fixed point math
* for the coordinate scaling.
* - OR together srcw and srch to get the MSB between the two
* - Next shift it up until it goes negative
* - Count the shifts and that will be the most accurate
* precision available for the fixed point math
* - a source coordinate of 1.0 will be (1 << shift)
* - srcw & srch will be (srcw << shift) and (srch << shift)
* and will not overflow
* Note that if srcw or srch are so large that they are
* negative numbers before shifting, then:
* - shift will be 0
* - tilesize will end up being 1x1 tiles
* - we will brute force calculate the source location
* of every destination pixel using the TILESTART and
* SRCLOC macros in this function and then call the
* scale helper function to copy one pixel at a time.
* - TILESTART involves mostly jdouble calculations so
* it should not have integer overflow problems.
*/
shift = 0;
if (sxinc > 0) {
while ((sxinc <<= 1) > 0) {
shift++;
}
}
/*
* Now determine the scaled integer increments used to traverse
* the source image for each destination pixel. Our shift value
* has been calculated above so that any location within the
* destination image can be represented as a scaled integer
* without incurring integer overflow.
*
* But we also need to worry about overflow of the sxinc and syinc
* parameters. We already know that "srcw<<shift" and "srch<<shift"
* cannot overflow a jint, and the only time that sxinc and syinc
* can be larger than those two values is if ddy2-ddy1 or ddx2-ddx1
* are smaller than 1. Since this situation implies that the
* output area is no more than one pixel wide or tall, then we are
* stepping by distances that are at least the size of the image
* and only one destination pixel will ever be rendered - thus the
* amount by which we step is largely irrelevant since after
* drawing the first "in bounds" pixel, we will step completely
* out of the source image and render nothing more. As a result,
* we assign the appropriate "size of image" stepping parameter
* for any scale to smaller than one device pixel.
*/
return;
}
{
return;
}
/*
* Only refine lower bounds if lower source coordinate was clipped
* because the math will work out to be exactly idx1, idy1 if not.
* Always refine upper bounds since we want to make sure not to
* overstep the source bounds based on the tiled iteration math.
*
* For underflow cases, simply check if the SRCLOC for the single
* destination pixel maps inside the source bounds. If it does,
* we render that pixel row or column (and only that pixel row
* or column). If it does not, we render nothing.
*/
if (xunderflow) {
}
} else {
? idx1
}
if (yunderflow) {
}
} else {
? idy1
}
if (!Region_IsRectangular(&clipInfo)) {
}
return;
}
{
{
/* Do everything in one tile */
void *pDst;
}
}
}
} else {
/* Break each clip span into tiles for better accuracy. */
void *pDst;
{
/* Clip span to Y range of current tile */
/* Find scaled source coordinate of first pixel */
}
{
/* Clip span to X range of current tile */
/* Find scaled source coordinate of first pixel */
}
}
}
}
}
}
}
}