/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* 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.
*/
package com.sun.javafx.font.directwrite;
import com.sun.javafx.font.PrismFontFactory;
import com.sun.javafx.font.PrismFontFile;
import com.sun.javafx.text.GlyphLayout;
import com.sun.prism.GraphicsPipeline;
public class DWFactory extends PrismFontFactory {
/* Factories (Singletons) */
private static IDWriteFactory DWRITE_FACTORY = null;
private static IDWriteFontCollection FONT_COLLECTION = null;
private static IWICImagingFactory WIC_FACTORY = null;
private static ID2D1Factory D2D_FACTORY = null;
private static Thread d2dThread;
public static PrismFontFactory getFactory() {
/* DirectWrite is not available on Windows Vista SP2 (JFX minimal
* requirement on Windows) without 'Platform Update'.
* To workaround this limitation this method first checks if a
* IDWriteFactory can be created. The DWriteCreateFactory is a dynamic
* method which fails gracefully (returns NULL) when the system does
* not support DirectWrite.
*/
if (getDWriteFactory() == null) {
/* Returning null here indicates to the PrismFontFactory
* to throw an Error . */
return null;
}
return new DWFactory();
}
private DWFactory() {
}
@Override
protected PrismFontFile createFontFile(String name, String filename,
int fIndex, boolean register,
boolean embedded, boolean copy,
boolean tracked) throws Exception {
return new DWFontFile(name, filename, fIndex, register,
embedded, copy, tracked);
}
@Override public GlyphLayout createGlyphLayout() {
return new DWGlyphLayout();
}
@Override
protected boolean registerEmbeddedFont(String path) {
IDWriteFactory factory = DWFactory.getDWriteFactory();
IDWriteFontFile fontFile = factory.CreateFontFileReference(path);
if (fontFile == null) return false;
boolean[] isSupportedFontType = new boolean[1];
int[] fontFileType = new int[1];
int[] fontFaceType = new int[1];
int[] numberOfFaces = new int[1];
int hr = fontFile.Analyze(isSupportedFontType, fontFileType, fontFaceType, numberOfFaces);
fontFile.Release();
if (hr != OS.S_OK) return false;
return isSupportedFontType[0];
}
static IDWriteFactory getDWriteFactory() {
/* Using multi threaded DWrite factory as the JFX thread requires access
* to DWrite resources for measuring and the Prism thread for rendering */
if (DWRITE_FACTORY == null) {
DWRITE_FACTORY = OS.DWriteCreateFactory(OS.DWRITE_FACTORY_TYPE_SHARED);
}
return DWRITE_FACTORY;
}
static IDWriteFontCollection getFontCollection() {
if (FONT_COLLECTION == null) {
FONT_COLLECTION = getDWriteFactory().GetSystemFontCollection(false);
}
return FONT_COLLECTION;
}
private static void checkThread() {
/* Note: It is possible for the correct thread to acquire the factory and
* hand it over to some other thread. This would be a programming error
* and it is not check by this implementation. */
Thread current = Thread.currentThread();
if (d2dThread == null) {
d2dThread = current;
}
if (d2dThread != current) {
throw new IllegalStateException(
"This operation is not permitted on the current thread ["
+ current.getName() + "]");
}
}
static synchronized IWICImagingFactory getWICFactory() {
checkThread();
/* Using single threaded WIC Factory as it should only be used by the rendering thread */
if (WIC_FACTORY == null) {
/* Initialize COM in order to create a WICImagingFactory.
* It runs on the prism thread and expects no other code in this thread
* to interface with COM. */
if (!OS.CoInitializeEx(OS.COINIT_APARTMENTTHREADED | OS.COINIT_DISABLE_OLE1DDE)) {
return null;
}
WIC_FACTORY = OS.WICCreateImagingFactory();
if (WIC_FACTORY == null) {
return null;
}
GraphicsPipeline.getPipeline().addDisposeHook(() -> {
checkThread();
WIC_FACTORY.Release();
OS.CoUninitialize();
WIC_FACTORY = null;
});
}
return WIC_FACTORY;
}
static synchronized ID2D1Factory getD2DFactory() {
checkThread();
/* Using single threaded D2D Factory as it should only be used by the rendering thread */
if (D2D_FACTORY == null) {
D2D_FACTORY = OS.D2D1CreateFactory(OS.D2D1_FACTORY_TYPE_SINGLE_THREADED);
}
return D2D_FACTORY;
}
}