diff options
Diffstat (limited to 'src/windows/native/sun/font/lcdglyphDW.cpp')
-rw-r--r-- | src/windows/native/sun/font/lcdglyphDW.cpp | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/src/windows/native/sun/font/lcdglyphDW.cpp b/src/windows/native/sun/font/lcdglyphDW.cpp new file mode 100644 index 0000000000..bfcb732885 --- /dev/null +++ b/src/windows/native/sun/font/lcdglyphDW.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2016 JetBrains s.r.o. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 <stdio.h> +#include <malloc.h> +#include <math.h> +#include <windows.h> +#include <winuser.h> +#include <Dwrite.h> + +#include <jni.h> +#include <jni_util.h> +#include <jlong_md.h> +#include <sizecalc.h> +#include <sun_font_FileFontStrike.h> + +#include "fontscalerdefs.h" + +extern "C" { + +#define FREE \ + if (target != NULL) { \ + target->Release(); \ + }\ + if (params != NULL) { \ + params->Release(); \ + }\ + if (defaultParams != NULL) { \ + defaultParams->Release(); \ + }\ + if (face != NULL) { \ + face->Release(); \ + }\ + if (font != NULL) { \ + font->Release(); \ + }\ + if (interop != NULL) { \ + interop->Release(); \ + }\ + if (factory != NULL) { \ + factory->Release(); \ + } + +#define FREE_AND_RETURN \ + FREE\ + return (jlong)0; + +JNIEXPORT jboolean JNICALL +Java_sun_font_FileFontStrike_isDirectWriteAvailable(JNIEnv *env, jclass unused) { + // This is an equivalent of IsWindows7OrGreater defined in VersionHelpers.h + + OSVERSIONINFOEXW osvi; + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); + osvi.dwMajorVersion = 6; + osvi.dwMinorVersion = 1; + + DWORDLONG conditionMask = VerSetConditionMask(VerSetConditionMask(0, + VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL); + + BOOL result = VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION, conditionMask); + return result ? JNI_TRUE : JNI_FALSE; +} + +JNIEXPORT jlong JNICALL +Java_sun_font_FileFontStrike__1getGlyphImageFromWindowsUsingDirectWrite +(JNIEnv *env, jobject unused, jstring fontFamily, jint style, jint size, jint glyphCode, + jint measuringMode, jint renderingMode, jfloat clearTypeLevel, jfloat enhancedContrast, jfloat gamma, jint pixelGeometry) { + // variables cleared by FREE macro + IDWriteFactory* factory = NULL; + IDWriteGdiInterop* interop = NULL; + IDWriteFont* font = NULL; + IDWriteFontFace* face = NULL; + IDWriteRenderingParams* defaultParams = NULL; + IDWriteRenderingParams* params = NULL; + IDWriteBitmapRenderTarget* target = NULL; + + LOGFONTW lf; + memset(&lf, 0, sizeof(LOGFONTW)); + lf.lfWeight = (style & 1) ? FW_BOLD : FW_NORMAL; + lf.lfItalic = (style & 2) ? TRUE : FALSE; + + int nameLen = env->GetStringLength(fontFamily); + if (nameLen >= (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) { + FREE_AND_RETURN + } + env->GetStringRegion(fontFamily, 0, nameLen, lf.lfFaceName); + lf.lfFaceName[nameLen] = '\0'; + + HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, + __uuidof(IDWriteFactory), + reinterpret_cast<IUnknown**>(&factory)); + if (FAILED(hr)) { + FREE_AND_RETURN + } + hr = factory->GetGdiInterop(&interop); + if (FAILED(hr)) { + FREE_AND_RETURN + } + hr = interop->CreateFontFromLOGFONT(&lf, &font); + if (FAILED(hr)) { + FREE_AND_RETURN + } + hr = font->CreateFontFace(&face); + if (FAILED(hr)) { + FREE_AND_RETURN + } + hr = factory->CreateRenderingParams(&defaultParams); + if (FAILED(hr)) { + FREE_AND_RETURN + } + hr = factory->CreateCustomRenderingParams( + gamma > 0 && gamma <= 256 ? gamma : defaultParams->GetGamma(), + enhancedContrast >= 0 ? enhancedContrast : defaultParams->GetEnhancedContrast(), + clearTypeLevel >= 0 && clearTypeLevel <= 1 ? clearTypeLevel : defaultParams->GetClearTypeLevel(), + pixelGeometry >= 0 && pixelGeometry <= 2 ? (DWRITE_PIXEL_GEOMETRY)pixelGeometry : defaultParams->GetPixelGeometry(), + renderingMode >= 0 && renderingMode <= 6 ? (DWRITE_RENDERING_MODE)renderingMode : defaultParams->GetRenderingMode(), + ¶ms); + if (FAILED(hr)) { + FREE_AND_RETURN + } + + UINT16 indices[] = {(UINT16)glyphCode}; + FLOAT advances[] = {0}; + DWRITE_GLYPH_OFFSET offsets[] = {{0, 0}}; + DWRITE_GLYPH_RUN glyphRun; + glyphRun.fontFace = face; + glyphRun.fontEmSize = (FLOAT)size; + glyphRun.glyphCount = 1; + glyphRun.glyphIndices = indices; + glyphRun.glyphAdvances = advances; + glyphRun.glyphOffsets = offsets; + glyphRun.isSideways = FALSE; + glyphRun.bidiLevel = 0; + + DWRITE_FONT_METRICS fontMetrics; + face->GetMetrics(&fontMetrics); + FLOAT pxPerDU = ((FLOAT)size) / fontMetrics.designUnitsPerEm; + + DWRITE_GLYPH_METRICS metrics[1]; + hr = face->GetDesignGlyphMetrics(indices, 1, metrics, FALSE); + if (FAILED(hr)) { + FREE_AND_RETURN + } + + // trying to derive required bitmap size from glyph metrics (adding several spare pixels on each border) + // if that will fail, we'll perform a second attempt based on the output of DrawGlyphRun + int width = (int)((metrics[0].advanceWidth - metrics[0].leftSideBearing - metrics[0].rightSideBearing) * pxPerDU) + 10; + int height = (int)((metrics[0].advanceHeight - metrics[0].topSideBearing - metrics[0].bottomSideBearing) * pxPerDU) + 10; + int x = (int)(-metrics[0].leftSideBearing * pxPerDU) + 5; + int y = (int)((metrics[0].verticalOriginY - metrics[0].topSideBearing) * pxPerDU) + 5; + RECT bbRect; + + for (int attempt = 0; attempt < 2 && target == NULL; attempt++) { + hr = interop->CreateBitmapRenderTarget(NULL, width, height, &target); + if (FAILED(hr)) { + FREE_AND_RETURN + } + hr = target->DrawGlyphRun((FLOAT)x, + (FLOAT)y, + measuringMode >= 0 && measuringMode <= 2 ? (DWRITE_MEASURING_MODE)measuringMode : DWRITE_MEASURING_MODE_NATURAL, + &glyphRun, + params, + RGB(255,255,255), + &bbRect); + if (FAILED(hr) || bbRect.left > bbRect.right || bbRect.top > bbRect.bottom + || attempt > 0 && (bbRect.left < 0 || bbRect.top < 0 || bbRect.right > width || bbRect.bottom > height)) { + FREE_AND_RETURN + } + if (bbRect.left < 0 || bbRect.top < 0 || bbRect.right > width || bbRect.bottom > height) { + target->Release(); + target = NULL; + if (bbRect.right > width) width = bbRect.right; + if (bbRect.bottom > height) height = bbRect.bottom; + if (bbRect.left < 0) { + width -= bbRect.left; + x -= bbRect.left; + } + if (bbRect.top < 0) { + height -= bbRect.top; + y -= bbRect.top; + } + } + } + + HDC glyphDC = target->GetMemoryDC(); + HGDIOBJ glyphBitmap = GetCurrentObject(glyphDC, OBJ_BITMAP); + if (glyphBitmap == NULL) { + FREE_AND_RETURN + } + DIBSECTION dibSection; + if (GetObject(glyphBitmap, sizeof(DIBSECTION), &dibSection) == 0) { + FREE_AND_RETURN + } + + int glyphWidth = bbRect.right - bbRect.left; + int glyphHeight = bbRect.bottom - bbRect.top; + int glyphBytesWidth = glyphWidth * 3; + GlyphInfo* glyphInfo = (GlyphInfo*)SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(GlyphInfo), glyphBytesWidth, glyphHeight); + if (glyphInfo == NULL) { + FREE_AND_RETURN + } + glyphInfo->managed = UNMANAGED_GLYPH; + glyphInfo->cellInfo = NULL; + glyphInfo->image = (unsigned char*)glyphInfo+sizeof(GlyphInfo); + glyphInfo->rowBytes = glyphBytesWidth; + glyphInfo->width = glyphWidth; + glyphInfo->height = glyphHeight; + glyphInfo->advanceX = (float)((int)(metrics[0].advanceWidth * pxPerDU + 0.5)); + glyphInfo->advanceY = 0; + glyphInfo->topLeftX = (float)(bbRect.left - x); + glyphInfo->topLeftY = (float)(bbRect.top - y); + + int srcRowBytes = width * 4; + unsigned char* srcPtr = (unsigned char*) dibSection.dsBm.bmBits + srcRowBytes * bbRect.top; + unsigned char* destPtr = glyphInfo->image; + for (int y = 0; y < glyphHeight; y++) { + srcPtr += bbRect.left * 4; + for (int x = 0; x < glyphWidth; x++) { + // converting from BGRA to RGB + unsigned char b = *srcPtr++; + unsigned char g = *srcPtr++; + unsigned char r = *srcPtr++; + srcPtr++; + *destPtr++ = r; + *destPtr++ = g; + *destPtr++ = b; + } + srcPtr += (width - bbRect.right) * 4; + } + + FREE + return ptr_to_jlong(glyphInfo); +} + +} // extern "C"
\ No newline at end of file |