aboutsummaryrefslogtreecommitdiff
path: root/src/windows/native/sun/font/lcdglyphDW.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/native/sun/font/lcdglyphDW.cpp')
-rw-r--r--src/windows/native/sun/font/lcdglyphDW.cpp258
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(),
+ &params);
+ 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