示例#1
0
HRESULT
D3DTR_DrawGlyphList(D3DContext *d3dc, D3DSDOps *dstOps,
                    jint totalGlyphs, jboolean usePositions,
                    jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
                    jfloat glyphListOrigX, jfloat glyphListOrigY,
                    unsigned char *images, unsigned char *positions)
{
    int glyphCounter;
    HRESULT res = S_OK;
    J2dTraceLn(J2D_TRACE_INFO, "D3DTR_DrawGlyphList");

    RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
    RETURN_STATUS_IF_NULL(d3dc->Get3DDevice(), E_FAIL);
    RETURN_STATUS_IF_NULL(dstOps, E_FAIL);
    RETURN_STATUS_IF_NULL(images, E_FAIL);
    if (usePositions) {
        RETURN_STATUS_IF_NULL(positions, E_FAIL);
    }

    glyphMode = MODE_NOT_INITED;
    isCachedDestValid = JNI_FALSE;

    for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
        jint x, y;
        jfloat glyphx, glyphy;
        jboolean grayscale;
        GlyphInfo *ginfo = (GlyphInfo *)jlong_to_ptr(NEXT_LONG(images));

        if (ginfo == NULL) {
            // this shouldn't happen, but if it does we'll just break out...
            J2dRlsTraceLn(J2D_TRACE_ERROR,
                          "D3DTR_DrawGlyphList: glyph info is null");
            break;
        }

        grayscale = (ginfo->rowBytes == ginfo->width);

        if (usePositions) {
            jfloat posx = NEXT_FLOAT(positions);
            jfloat posy = NEXT_FLOAT(positions);
            glyphx = glyphListOrigX + posx + ginfo->topLeftX;
            glyphy = glyphListOrigY + posy + ginfo->topLeftY;
            FLOOR_ASSIGN(x, glyphx);
            FLOOR_ASSIGN(y, glyphy);
        } else {
            glyphx = glyphListOrigX + ginfo->topLeftX;
            glyphy = glyphListOrigY + ginfo->topLeftY;
            FLOOR_ASSIGN(x, glyphx);
            FLOOR_ASSIGN(y, glyphy);
            glyphListOrigX += ginfo->advanceX;
            glyphListOrigY += ginfo->advanceY;
        }

        if (ginfo->image == NULL) {
            continue;
        }

        if (grayscale) {
            // grayscale or monochrome glyph data
            if (ginfo->width <= D3DTR_CACHE_CELL_WIDTH &&
                ginfo->height <= D3DTR_CACHE_CELL_HEIGHT &&
                SUCCEEDED(d3dc->InitGrayscaleGlyphCache()))
            {
                res = D3DTR_DrawGrayscaleGlyphViaCache(d3dc, ginfo, x, y);
            } else {
                res = D3DTR_DrawGrayscaleGlyphNoCache(d3dc, ginfo, x, y);
            }
        } else {
            // LCD-optimized glyph data
            jint rowBytesOffset = 0;

            if (subPixPos) {
                jint frac = (jint)((glyphx - x) * 3);
                if (frac != 0) {
                    rowBytesOffset = 3 - frac;
                    x += 1;
                }
            }

            if (rowBytesOffset == 0 &&
                ginfo->width <= D3DTR_CACHE_CELL_WIDTH &&
                ginfo->height <= D3DTR_CACHE_CELL_HEIGHT &&
                SUCCEEDED(d3dc->InitLCDGlyphCache()))
            {
                res = D3DTR_DrawLCDGlyphViaCache(d3dc, dstOps,
                                                 ginfo, x, y,
                                                 glyphCounter, totalGlyphs,
                                                 rgbOrder, lcdContrast);
            } else {
                res = D3DTR_DrawLCDGlyphNoCache(d3dc, dstOps,
                                                ginfo, x, y,
                                                rowBytesOffset,
                                                rgbOrder, lcdContrast);
            }
        }

        if (FAILED(res)) {
            break;
        }
    }

    D3DTR_DisableGlyphModeState(d3dc);
    return res;
}
示例#2
0
GlyphBlitVector* setupBlitVector(JNIEnv *env, jobject glyphlist) {

    int g, bytesNeeded;
    jlong *imagePtrs;
    jfloat* positions = NULL;
    GlyphInfo *ginfo;
    GlyphBlitVector *gbv;

    jfloat x = (*env)->GetFloatField(env, glyphlist, sunFontIDs.glyphListX);
    jfloat y = (*env)->GetFloatField(env, glyphlist, sunFontIDs.glyphListY);
    jint len =  (*env)->GetIntField(env, glyphlist, sunFontIDs.glyphListLen);
    jlongArray glyphImages = (jlongArray)
        (*env)->GetObjectField(env, glyphlist, sunFontIDs.glyphImages);
    jfloatArray glyphPositions =
      (*env)->GetBooleanField(env, glyphlist, sunFontIDs.glyphListUsePos)
        ? (jfloatArray)
      (*env)->GetObjectField(env, glyphlist, sunFontIDs.glyphListPos)
        : NULL;

    bytesNeeded = sizeof(GlyphBlitVector)+sizeof(ImageRef)*len;
    gbv = (GlyphBlitVector*)malloc(bytesNeeded);
    gbv->numGlyphs = len;
    gbv->glyphs = (ImageRef*)((unsigned char*)gbv+sizeof(GlyphBlitVector));

    imagePtrs = (*env)->GetPrimitiveArrayCritical(env, glyphImages, NULL);
    if (imagePtrs == NULL) {
        free(gbv);
        return (GlyphBlitVector*)NULL;
    }

    /* Add 0.5 to x and y and then use floor (or an equivalent operation)
     * to round down the glyph positions to integral pixel positions.
     */
    x += 0.5f;
    y += 0.5f;
    if (glyphPositions) {
        int n = -1;

        positions =
          (*env)->GetPrimitiveArrayCritical(env, glyphPositions, NULL);
        if (positions == NULL) {
            (*env)->ReleasePrimitiveArrayCritical(env, glyphImages,
                                                  imagePtrs, JNI_ABORT);
            free(gbv);
            return (GlyphBlitVector*)NULL;
        }

        for (g=0; g<len; g++) {
            jfloat px = x + positions[++n];
            jfloat py = y + positions[++n];

            ginfo = (GlyphInfo*)imagePtrs[g];
            gbv->glyphs[g].glyphInfo = ginfo;
            gbv->glyphs[g].pixels = ginfo->image;
            gbv->glyphs[g].width = ginfo->width;
            gbv->glyphs[g].rowBytes = ginfo->rowBytes;
            gbv->glyphs[g].height = ginfo->height;
            FLOOR_ASSIGN(gbv->glyphs[g].x, px + ginfo->topLeftX);
            FLOOR_ASSIGN(gbv->glyphs[g].y, py + ginfo->topLeftY);
        }
        (*env)->ReleasePrimitiveArrayCritical(env,glyphPositions,
                                              positions, JNI_ABORT);
    } else {
        for (g=0; g<len; g++) {
            ginfo = (GlyphInfo*)imagePtrs[g];
            gbv->glyphs[g].glyphInfo = ginfo;
            gbv->glyphs[g].pixels = ginfo->image;
            gbv->glyphs[g].width = ginfo->width;
            gbv->glyphs[g].rowBytes = ginfo->rowBytes;
            gbv->glyphs[g].height = ginfo->height;
            FLOOR_ASSIGN(gbv->glyphs[g].x, x + ginfo->topLeftX);
            FLOOR_ASSIGN(gbv->glyphs[g].y, y + ginfo->topLeftY);

            /* copy image data into this array at x/y locations */
            x += ginfo->advanceX;
            y += ginfo->advanceY;
        }
    }

    (*env)->ReleasePrimitiveArrayCritical(env, glyphImages, imagePtrs,
                                          JNI_ABORT);
    return gbv;
}
示例#3
0
void
OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps,
                    jint totalGlyphs, jboolean usePositions,
                    jboolean subPixPos, jboolean rgbOrder, jint lcdContrast,
                    jfloat glyphListOrigX, jfloat glyphListOrigY,
                    unsigned char *images, unsigned char *positions)
{
    int glyphCounter;

    J2dTraceLn(J2D_TRACE_INFO, "OGLTR_DrawGlyphList");

    RETURN_IF_NULL(oglc);
    RETURN_IF_NULL(dstOps);
    RETURN_IF_NULL(images);
    if (usePositions) {
        RETURN_IF_NULL(positions);
    }

    glyphMode = MODE_NOT_INITED;
    isCachedDestValid = JNI_FALSE;

    for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
        jint x, y;
        jfloat glyphx, glyphy;
        jboolean grayscale, ok;
        GlyphInfo *ginfo = (GlyphInfo *)jlong_to_ptr(NEXT_LONG(images));

        if (ginfo == NULL) {
            // this shouldn't happen, but if it does we'll just break out...
            J2dRlsTraceLn(J2D_TRACE_ERROR,
                          "OGLTR_DrawGlyphList: glyph info is null");
            break;
        }

        grayscale = (ginfo->rowBytes == ginfo->width);

        if (usePositions) {
            jfloat posx = NEXT_FLOAT(positions);
            jfloat posy = NEXT_FLOAT(positions);
            glyphx = glyphListOrigX + posx + ginfo->topLeftX;
            glyphy = glyphListOrigY + posy + ginfo->topLeftY;
            FLOOR_ASSIGN(x, glyphx);
            FLOOR_ASSIGN(y, glyphy);
        } else {
            glyphx = glyphListOrigX + ginfo->topLeftX;
            glyphy = glyphListOrigY + ginfo->topLeftY;
            FLOOR_ASSIGN(x, glyphx);
            FLOOR_ASSIGN(y, glyphy);
            glyphListOrigX += ginfo->advanceX;
            glyphListOrigY += ginfo->advanceY;
        }

        if (ginfo->image == NULL) {
            continue;
        }

        if (grayscale) {
            // grayscale or monochrome glyph data
            if (cacheStatus != CACHE_LCD &&
                ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
                ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
            {
                ok = OGLTR_DrawGrayscaleGlyphViaCache(oglc, ginfo, x, y);
            } else {
                ok = OGLTR_DrawGrayscaleGlyphNoCache(oglc, ginfo, x, y);
            }
        } else {
            // LCD-optimized glyph data
            jint rowBytesOffset = 0;

            if (subPixPos) {
                jint frac = (jint)((glyphx - x) * 3);
                if (frac != 0) {
                    rowBytesOffset = 3 - frac;
                    x += 1;
                }
            }

            if (rowBytesOffset == 0 &&
                cacheStatus != CACHE_GRAY &&
                ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
                ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
            {
                ok = OGLTR_DrawLCDGlyphViaCache(oglc, dstOps,
                                                ginfo, x, y,
                                                glyphCounter, totalGlyphs,
                                                rgbOrder, lcdContrast);
            } else {
                ok = OGLTR_DrawLCDGlyphNoCache(oglc, dstOps,
                                               ginfo, x, y,
                                               rowBytesOffset,
                                               rgbOrder, lcdContrast);
            }
        }

        if (!ok) {
            break;
        }
    }

    OGLTR_DisableGlyphModeState();
}
示例#4
0
/*
 *  LCD text utilises a filter which spreads energy to adjacent subpixels.
 *  So we add 3 bytes (one whole pixel) of padding at the start of every row
 *  to hold energy from the very leftmost sub-pixel.
 *  This is to the left of the intended glyph image position so LCD text also
 *  adjusts the top-left X position of the padded image one pixel to the left
 *  so a glyph image is drawn in the same place it would be if the padding
 *  were not present.
 *
 *  So in the glyph cache for LCD text the first two bytes of every row are
 *  zero.
 *  We make use of this to be able to adjust the rendering position of the
 *  text when the client specifies a fractional metrics sub-pixel positioning
 *  rendering hint.
 *
 *  So the first 6 bytes in a cache row looks like :
 *  00 00 Ex G0 G1 G2
 *
 *  where
 *  00 are the always zero bytes
 *  Ex is extra energy spread from the glyph into the left padding pixel.
 *  Gn are the RGB component bytes of the first pixel of the glyph image
 *  For an RGB display G0 is the red component, etc.
 *
 *  If a glyph is drawn at X=12 then the G0 G1 G2 pixel is placed at that
 *  position : ie G0 is drawn in the first sub-pixel at X=12
 *
 *  Draw at X=12,0
 *  PIXEL POS 11 11 11 12 12 12 13 13 13
 *  SUBPX POS  0  1  2  0  1  2  0  1  2
 *            00 00 Ex G0 G1 G2
 *
 *  If a sub-pixel rounded glyph position is calculated as being X=12.33 -
 *  ie 12 and one-third pixels, we want the result to look like this :
 *  Draw at X=12,1
 *  PIXEL POS 11 11 11 12 12 12 13 13 13
 *  SUBPX POS  0  1  2  0  1  2  0  1  2
 *               00 00 Ex G0 G1 G2
 *
 *  ie the G0 byte is moved one sub-pixel to the right.
 *  To do this we need to make two adjustments :
 *  - set X=X+1
 *  - set start of scan row to start+2, ie index past the two zero bytes
 *  ie we don't need the 00 00 bytes at all any more. Rendering start X
 *  can skip over those.
 *
 *  Lets look at the final case :
 *  If a sub-pixel rounded glyph position is calculated as being X=12.67 -
 *  ie 12 and two-third pixels, we want the result to look like this :
 *  Draw at X=12,2
 *  PIXEL POS 11 11 11 12 12 12 13 13 13
 *  SUBPX POS  0  1  2  0  1  2  0  1  2
 *                  00 00 Ex G0 G1 G2
 *
 *  ie the G0 byte is moved two sub-pixels to the right, so that the image
 *  starts at 12.67
 *  To do this we need to make these two adjustments :
 *  - set X=X+1
 *  - set start of scan row to start+1, ie index past the first zero byte
 *  In this case the second of the 00 bytes is used as a no-op on the first
 *   red sub-pixel position.
 *
 *  The final adjustment needed to make all this work is note that if
 *  we moved the start of row one or two bytes in we will go one or two bytes
 *  past the end of the row. So the glyph cache needs to have 2 bytes of
 *  zero padding at the end of each row. This is the extra memory cost to
 *  accommodate this algorithm.
 *
 *  The resulting text is perhaps fractionally better in overall perception
 *  than rounding to the whole pixel grid, as a few issues arise.
 *
 *  * the improvement in inter-glyph spacing as well as being limited
 *  to 1/3 pixel resolution, is also limited because the glyphs were hinted
 *  so they fit to the whole pixel grid. It may be worthwhile to pursue
 *  disabling x-axis gridfitting.
 *
 *  * an LCD display may have gaps between the pixels that are greater
 *  than the subpixels. Thus for thin stemmed fonts, if the shift causes
 *  the "heart" of a stem to span whole pixels it may appear more diffuse -
 *  less sharp. Eliminating hinting would probably not make this worse - in
 *  effect we have already doing that here. But it would improve the spacing.
 *
 *  * perhaps contradicting the above point in some ways, more diffuse glyphs
 *  are better at reducing colour fringing, but what appears to be more
 *  colour fringing in this FM case is more likely attributable to a greater
 *  likelihood for glyphs to abutt. In integer metrics or even whole pixel
 *  rendered fractional metrics, there's typically more space between the
 *  glyphs. Perhaps disabling X-axis grid-fitting will help with that.
 */
GlyphBlitVector* setupLCDBlitVector(JNIEnv *env, jobject glyphlist) {

    int g, bytesNeeded;
    jlong *imagePtrs;
    jfloat* positions = NULL;
    GlyphInfo *ginfo;
    GlyphBlitVector *gbv;

    jfloat x = (*env)->GetFloatField(env, glyphlist, sunFontIDs.glyphListX);
    jfloat y = (*env)->GetFloatField(env, glyphlist, sunFontIDs.glyphListY);
    jint len =  (*env)->GetIntField(env, glyphlist, sunFontIDs.glyphListLen);
    jlongArray glyphImages = (jlongArray)
        (*env)->GetObjectField(env, glyphlist, sunFontIDs.glyphImages);
    jfloatArray glyphPositions =
      (*env)->GetBooleanField(env, glyphlist, sunFontIDs.glyphListUsePos)
        ? (jfloatArray)
      (*env)->GetObjectField(env, glyphlist, sunFontIDs.glyphListPos)
        : NULL;
    jboolean subPixPos =
      (*env)->GetBooleanField(env,glyphlist, sunFontIDs.lcdSubPixPos);

    bytesNeeded = sizeof(GlyphBlitVector)+sizeof(ImageRef)*len;
    gbv = (GlyphBlitVector*)malloc(bytesNeeded);
    gbv->numGlyphs = len;
    gbv->glyphs = (ImageRef*)((unsigned char*)gbv+sizeof(GlyphBlitVector));

    imagePtrs = (*env)->GetPrimitiveArrayCritical(env, glyphImages, NULL);
    if (imagePtrs == NULL) {
        free(gbv);
        return (GlyphBlitVector*)NULL;
    }

    /* The position of the start of the text is adjusted up so
     * that we can round it to an integral pixel position for a
     * bitmap glyph or non-subpixel positioning, and round it to an
     * integral subpixel position for that case, hence 0.5/3 = 0.166667
     * Presently subPixPos means FM, and FM disables embedded bitmaps
     * Therefore if subPixPos is true we should never get embedded bitmaps
     * and the glyphlist will be homogenous. This test and the position
     * adjustments will need to be per glyph once this case becomes
     * heterogenous.
     * Also set subPixPos=false if detect a B&W bitmap as we only
     * need to test that on a per glyph basis once the list becomes
     * heterogenous
     */
    if (subPixPos && len > 0) {
        ginfo = (GlyphInfo*)imagePtrs[0];
        /* rowBytes==width tests if its a B&W or LCD glyph */
        if (ginfo->width == ginfo->rowBytes) {
            subPixPos = JNI_FALSE;
        }
    }
    if (subPixPos) {
        x += 0.1666667f;
        y += 0.1666667f;
    } else {
        x += 0.5f;
        y += 0.5f;
    }

     if (glyphPositions) {
        int n = -1;

        positions =
          (*env)->GetPrimitiveArrayCritical(env, glyphPositions, NULL);
        if (positions == NULL) {
            (*env)->ReleasePrimitiveArrayCritical(env, glyphImages,
                                                  imagePtrs, JNI_ABORT);
            free(gbv);
            return (GlyphBlitVector*)NULL;
        }

        for (g=0; g<len; g++) {
            jfloat px, py;

            ginfo = (GlyphInfo*)imagePtrs[g];
            gbv->glyphs[g].glyphInfo = ginfo;
            gbv->glyphs[g].pixels = ginfo->image;
            gbv->glyphs[g].width = ginfo->width;
            gbv->glyphs[g].rowBytes = ginfo->rowBytes;
            gbv->glyphs[g].height = ginfo->height;

            px = x + positions[++n];
            py = y + positions[++n];

            /*
             * Subpixel positioning may be requested for LCD text.
             *
             * Subpixel positioning can take place only in the direction in
             * which the subpixels increase the resolution.
             * So this is useful for the typical case of vertical stripes
             * increasing the resolution in the direction of the glyph
             * advances - ie typical horizontally laid out text.
             * If the subpixel stripes are horizontal, subpixel positioning
             * can take place only in the vertical direction, which isn't
             * as useful - you would have to be drawing rotated text on
             * a display which actually had that organisation. A pretty
             * unlikely combination.
             * So this is supported only for vertical stripes which
             * increase the horizontal resolution.
             * If in this case the client also rotates the text then there
             * will still be some benefit for small rotations. For 90 degree
             * rotation there's no horizontal advance and less benefit
             * from the subpixel rendering too.
             * The test for width==rowBytes detects the case where the glyph
             * is a B&W image obtained from an embedded bitmap. In that
             * case we cannot apply sub-pixel positioning so ignore it.
             * This is handled on a per glyph basis.
             */
            if (subPixPos) {
                int frac;
                float pos = px + ginfo->topLeftX;
                FLOOR_ASSIGN(gbv->glyphs[g].x, pos);
                /* Calculate the fractional pixel position - ie the subpixel
                 * position within the RGB/BGR triple. We are rounding to
                 * the nearest, even though we just do (int) since at the
                 * start of the loop the position was already adjusted by
                 * 0.5 (sub)pixels to get rounding.
                 * Thus the "fractional" position will be 0, 1 or 2.
                 * eg 0->0.32 is 0, 0.33->0.66 is 1, > 0.66->0.99 is 2.
                 * We can use an (int) cast here since the floor operation
                 * above guarantees us that the value is positive.
                 */
                frac = (int)((pos - gbv->glyphs[g].x)*3);
                if (frac == 0) {
                    /* frac rounded down to zero, so this is equivalent
                     * to no sub-pixel positioning.
                     */
                    gbv->glyphs[g].rowBytesOffset = 0;
                } else {
                    /* In this case we need to adjust both the position at
                     * which the glyph will be positioned by one pixel to the
                     * left and adjust the position in the glyph image row
                     * from which to extract the data
                     * Every glyph image row has 2 bytes padding
                     * on the right to account for this.
                     */
                    gbv->glyphs[g].rowBytesOffset = 3-frac;
                    gbv->glyphs[g].x += 1;
                }
            } else {
                FLOOR_ASSIGN(gbv->glyphs[g].x, px + ginfo->topLeftX);
                gbv->glyphs[g].rowBytesOffset = 0;
            }
            FLOOR_ASSIGN(gbv->glyphs[g].y, py + ginfo->topLeftY);
        }
        (*env)->ReleasePrimitiveArrayCritical(env,glyphPositions,
                                              positions, JNI_ABORT);
    } else {
        for (g=0; g<len; g++) {
            ginfo = (GlyphInfo*)imagePtrs[g];
            gbv->glyphs[g].glyphInfo = ginfo;
            gbv->glyphs[g].pixels = ginfo->image;
            gbv->glyphs[g].width = ginfo->width;
            gbv->glyphs[g].rowBytes = ginfo->rowBytes;
            gbv->glyphs[g].height = ginfo->height;

            if (subPixPos) {
                int frac;
                float pos = x + ginfo->topLeftX;
                FLOOR_ASSIGN(gbv->glyphs[g].x, pos);
                frac = (int)((pos - gbv->glyphs[g].x)*3);
                if (frac == 0) {
                    gbv->glyphs[g].rowBytesOffset = 0;
                } else {
                    gbv->glyphs[g].rowBytesOffset = 3-frac;
                    gbv->glyphs[g].x += 1;
                }
            } else {
                FLOOR_ASSIGN(gbv->glyphs[g].x, x + ginfo->topLeftX);
                gbv->glyphs[g].rowBytesOffset = 0;
            }
            FLOOR_ASSIGN(gbv->glyphs[g].y, y + ginfo->topLeftY);
            /* copy image data into this array at x/y locations */
            x += ginfo->advanceX;
            y += ginfo->advanceY;
        }
    }

    (*env)->ReleasePrimitiveArrayCritical(env, glyphImages, imagePtrs,
                                          JNI_ABORT);
    return gbv;
}