Adding support to trunk for building Skia using the Android NDK.

This CL depends on a subsequent CL to add the appropriate NDK
toolchain and system sources to the skia repo.

Review URL: http://codereview.appspot.com/5306089/
Review URL: http://codereview.appspot.com/5306089

git-svn-id: http://skia.googlecode.com/svn/trunk@2592 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
djsollen@google.com 2011-11-03 13:08:29 +00:00
parent d0601d2e7d
commit 58629291bc
21 changed files with 1218 additions and 104 deletions

View File

@ -10,7 +10,7 @@
#include "BenchSysTimer_windows.h"
#elif defined(SK_BUILD_FOR_MAC)
#include "BenchSysTimer_mach.h"
#elif defined(SK_BUILD_FOR_UNIX)
#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
#include "BenchSysTimer_posix.h"
#else
#include "BenchSysTimer_c.h"

View File

@ -247,7 +247,22 @@
'../experimental/iOSSampleApp/iPhone/MainWindow_iPhone.xib',
],
}],
[ 'skia_os == "android"', {
# TODO: This doesn't build properly yet, but it's getting there.
'type': 'shared_library',
'sources!': [
'../samplecode/SampleAnimator.cpp',
'../samplecode/SampleUnitMapper.cpp',
],
'dependencies!': [
'animator.gyp:animator',
'experimental.gyp:experimental',
],
'sources': [
# TODO add support for the android sample app
# '../samplecode/SampleApp_android.cpp',
],
}],
],
'msvs_settings': {
'VCLinkerTool': {

152
gyp/android_system.gyp Normal file
View File

@ -0,0 +1,152 @@
# This GYP file stores the dependencies necessary to build Skia on the Android
# platform. The OS doesn't provide many stable libraries as part of the
# distribution so we have to build a few of them ourselves.
#
# NOTE: We tried adding the gyp file to the android/ directory at the root of
# the Skia repo, but that resulted in the generated makefiles being created
# outside of the out directory. We may be able to move the bulk of this gyp
# to the /android directory and put a simple shim here, but that has yet to be
# tested.
{
# Define the location of the required Android sources, allowing for override
# in GYP_DEFINES.
#
# These sources are necessary because they must be built using the Android
# toolchain and they are not expected to be present on the host OS.
#
'variables': {
'android_repo%': '../../android_tools',
},
'android_repo%': '<(android_repo)',
'includes': [
'common.gypi',
],
'targets': [
{
'target_name': 'ft2',
'type': 'static_library',
'sources': [
'<(android_repo)/external/freetype/src/base/ftbbox.c',
'<(android_repo)/external/freetype/src/base/ftbitmap.c',
'<(android_repo)/external/freetype/src/base/ftglyph.c',
'<(android_repo)/external/freetype/src/base/ftlcdfil.c',
'<(android_repo)/external/freetype/src/base/ftstroke.c',
'<(android_repo)/external/freetype/src/base/ftxf86.c',
'<(android_repo)/external/freetype/src/base/ftbase.c',
'<(android_repo)/external/freetype/src/base/ftsystem.c',
'<(android_repo)/external/freetype/src/base/ftinit.c',
'<(android_repo)/external/freetype/src/base/ftgasp.c',
'<(android_repo)/external/freetype/src/base/ftfstype.c',
'<(android_repo)/external/freetype/src/raster/raster.c',
'<(android_repo)/external/freetype/src/sfnt/sfnt.c',
'<(android_repo)/external/freetype/src/smooth/smooth.c',
'<(android_repo)/external/freetype/src/autofit/autofit.c',
'<(android_repo)/external/freetype/src/truetype/truetype.c',
'<(android_repo)/external/freetype/src/cff/cff.c',
'<(android_repo)/external/freetype/src/psnames/psnames.c',
'<(android_repo)/external/freetype/src/pshinter/pshinter.c',
],
'include_dirs': [
'<(android_repo)/external/freetype/builds',
'<(android_repo)/external/freetype/include',
],
'cflags': [
'-W',
'-Wall',
'-fPIC',
'-DPIC',
'-DDARWIN_NO_CARBON',
'-DFT2_BUILD_LIBRARY',
'-O2',
],
'direct_dependent_settings': {
'include_dirs': [
'<(android_repo)/external/freetype/include', # For ft2build.h
],
}
},
{
'target_name': 'expat',
'type': 'static_library',
'sources': [
'<(android_repo)/external/expat/lib/xmlparse.c',
'<(android_repo)/external/expat/lib/xmlrole.c',
'<(android_repo)/external/expat/lib/xmltok.c',
],
'include_dirs': [
'<(android_repo)/external/expat',
'<(android_repo)/external/expat/lib',
],
'cflags': [
'-Wall',
'-Wmissing-prototypes',
'-Wstrict-prototypes',
'-fexceptions',
'-DHAVE_EXPAT_CONFIG_H',
],
'direct_dependent_settings': {
'include_dirs': [
'<(android_repo)/external/expat/lib', # For expat.h
],
}
},
{
'target_name': 'gif',
'type': 'static_library',
'sources': [
'<(android_repo)/external/gif/dgif_lib.c',
'<(android_repo)/external/gif/gifalloc.c',
'<(android_repo)/external/gif/gif_err.c',
],
'include_dirs': [
'<(android_repo)/external/gif',
],
'cflags': [
'-Wno-format',
'-DHAVE_CONFIG_H',
],
'direct_dependent_settings': {
'include_dirs': [
'<(android_repo)/external/gif',
],
}
},
{
'target_name': 'png',
'type': 'static_library',
'sources': [
'<(android_repo)/external/png/png.c',
'<(android_repo)/external/png/pngerror.c',
'<(android_repo)/external/png/pnggccrd.c',
'<(android_repo)/external/png/pngget.c',
'<(android_repo)/external/png/pngmem.c',
'<(android_repo)/external/png/pngpread.c',
'<(android_repo)/external/png/pngread.c',
'<(android_repo)/external/png/pngrio.c',
'<(android_repo)/external/png/pngrtran.c',
'<(android_repo)/external/png/pngrutil.c',
'<(android_repo)/external/png/pngset.c',
'<(android_repo)/external/png/pngtrans.c',
'<(android_repo)/external/png/pngvcrd.c',
'<(android_repo)/external/png/pngwio.c',
'<(android_repo)/external/png/pngwrite.c',
'<(android_repo)/external/png/pngwtran.c',
'<(android_repo)/external/png/pngwutil.c',
],
'include_dirs': [
'<(android_repo)/external/png',
],
'cflags': [
'-fvisibility=hidden',
],
'direct_dependent_settings': {
'include_dirs': [
'<(android_repo)/external/png',
],
}
},
]
}

View File

@ -40,12 +40,13 @@
'../bench/BenchSysTimer_mach.cpp',
],
}],
[ 'skia_os not in ["linux", "freebsd", "openbsd", "solaris"]', {
[ 'skia_os not in ["linux", "freebsd", "openbsd", "solaris", "android"]', {
'sources!': [
'../bench/BenchSysTimer_posix.h',
'../bench/BenchSysTimer_posix.cpp',
],
},{
}],
[ 'skia_os in ["linux", "freebsd", "openbsd", "solaris"]', {
'link_settings': {
'libraries': [
'-lrt',

View File

@ -135,6 +135,50 @@
},
},
],
['skia_os == "android"',
{
'defines': [
'ANDROID', # TODO: change these defines to SK_BUILD_FOR_ANDROID
'SK_BUILD_FOR_ANDROID',
'SK_BUILD_FOR_ANDROID_NDK',
],
'configurations': {
'Debug': {
'cflags': ['-g']
},
'Release': {
'cflags': ['-O2']
},
},
'libraries': [
'-lstdc++',
'-lm',
],
'conditions': [
[ 'skia_target_arch == "arm" and armv7 == 1', {
'defines': [
'__ARM_ARCH__=7',
],
'cflags': [
'-march=armv7-a',
],
'conditions': [
[ 'arm_neon == 1', {
'defines': [
'__ARM_HAVE_NEON',
],
'cflags': [
'-mfloat-abi=softfp',
'-mfpu=neon',
],
}],
],
}],
],
},
],
], # end 'conditions'
}

View File

@ -340,6 +340,24 @@
'../src/ports/SkTime_win.cpp',
],
}],
[ 'skia_os == "android"', {
'sources!': [
'../src/opts/opts_check_SSE2.cpp',
],
'sources': [
'../include/core/SkMMapStream.h',
'../src/core/SkMMapStream.cpp',
'../src/ports/SkThread_pthread.cpp',
'../src/ports/SkFontHost_android.cpp',
'../src/ports/SkFontHost_gamma.cpp',
'../src/ports/SkFontHost_FreeType.cpp',
'../src/ports/FontHostConfiguration_android.cpp',
],
'dependencies': [
'android_system.gyp:ft2',
'android_system.gyp:expat',
],
}],
],
'direct_dependent_settings': {
'include_dirs': [

View File

@ -114,6 +114,8 @@
'../src/gpu/SkGrTexturePixelRef.cpp',
'../src/gpu/SkNullGLContext.cpp',
'../src/gpu/android/SkNativeGLContext_android.cpp',
'../src/gpu/mac/SkNativeGLContext_mac.cpp',
'../src/gpu/win/SkNativeGLContext_win.cpp',
@ -270,6 +272,8 @@
'../src/gpu/unix/GrGLCreateNativeInterface_unix.cpp',
'../src/gpu/android/GrGLCreateNativeInterface_android.cpp',
'../src/gpu/mesa/GrGLCreateMesaInterface.cpp',
],
'defines': [
@ -327,6 +331,19 @@
'../src/gpu/GrGLCreateNativeInterface_none.cpp',
],
}],
[ 'skia_os == "android"', {
'sources!': [
'../src/gpu/GrGLDefaultInterface_none.cpp',
'../src/gpu/GrGLCreateNativeInterface_none.cpp',
],
'link_settings': {
'libraries': [
'-lGLESv2',
'-lEGL',
'-shared',
],
},
}],
],
},
],

View File

@ -116,7 +116,16 @@
},
# end libpng stuff
}],
[ 'skia_os == "android"', {
'sources!': [
'../src/images/SkImageDecoder_libjpeg.cpp',
'../src/images/SkJpegUtility.cpp',
],
'dependencies': [
'android_system.gyp:gif',
'android_system.gyp:png',
],
}],
],
'direct_dependent_settings': {
'include_dirs': [

View File

@ -35,11 +35,35 @@
'-msse2',
],
}],
],
'sources': [
'../src/opts/SkBitmapProcState_opts_SSE2.cpp',
'../src/opts/SkBlitRow_opts_SSE2.cpp',
'../src/opts/SkUtils_opts_SSE2.cpp',
[ 'skia_target_arch != "arm"', {
'sources': [
'../src/opts/SkBitmapProcState_opts_SSE2.cpp',
'../src/opts/SkBlitRow_opts_SSE2.cpp',
'../src/opts/SkUtils_opts_SSE2.cpp',
],
}],
[ 'skia_target_arch == "arm" and armv7 == 1', {
# The assembly uses the frame pointer register (r7 in Thumb/r11 in
# ARM), the compiler doesn't like that.
'cflags!': [
'-fno-omit-frame-pointer',
],
'cflags': [
'-fomit-frame-pointer',
],
'sources': [
'../src/opts/SkBitmapProcState_opts_arm.cpp',
'../src/opts/SkBlitRow_opts_arm.cpp',
'../src/opts/SkUtils_opts_none.cpp',
],
}],
[ 'skia_target_arch == "arm" and armv7 != 1', {
'sources': [
'../src/opts/SkBitmapProcState_opts_none.cpp',
'../src/opts/SkBlitRow_opts_none.cpp',
'../src/opts/SkUtils_opts_none.cpp',
],
}],
],
},
],

View File

@ -33,7 +33,7 @@
'../src/xml/SkXMLPullParser.cpp', #if 0 around class decl in header
],
'conditions': [
[ 'skia_os in ["win", "mac", "linux", "freebsd", "openbsd", "solaris"]', {
[ 'skia_os in ["win", "mac", "linux", "freebsd", "openbsd", "solaris", "android"]', {
'sources!': [
# no jsapi.h by default on system
'../include/xml/SkJS.h',

View File

@ -13,7 +13,7 @@
#include "SkString.h"
#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
#include <dirent.h>
#endif
@ -58,7 +58,7 @@ public:
#ifdef SK_BUILD_FOR_WIN
HANDLE fHandle;
uint16_t* fPath16;
#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
DIR* fDIR;
SkString fPath, fSuffix;
#endif

View File

@ -16,7 +16,7 @@
//////////////////////////////////////////////////////////////////////
#if !defined(SK_BUILD_FOR_ANDROID_NDK) && !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_PALM) && !defined(SK_BUILD_FOR_WINCE) && !defined(SK_BUILD_FOR_WIN32) && !defined(SK_BUILD_FOR_SYMBIAN) && !defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_SDL) && !defined(SK_BUILD_FOR_BREW)
#if !defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_NDK) && !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_PALM) && !defined(SK_BUILD_FOR_WINCE) && !defined(SK_BUILD_FOR_WIN32) && !defined(SK_BUILD_FOR_SYMBIAN) && !defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_SDL) && !defined(SK_BUILD_FOR_BREW)
#ifdef __APPLE__
#include "TargetConditionals.h"
@ -36,7 +36,7 @@
#define SK_BUILD_FOR_IOS
#elif defined(ANDROID_NDK)
#define SK_BUILD_FOR_ANDROID_NDK
#elif defined(ANROID)
#elif defined(ANDROID)
#define SK_BUILD_FOR_ANDROID
#else
#define SK_BUILD_FOR_MAC
@ -44,6 +44,15 @@
#endif
/* Even if the user only defined the NDK variant we still need to build
* the default Android code. Therefore, when attempting to include/exclude
* something from the NDK variant check first that we are building for
* Android then check the status of the NDK define.
*/
#if defined(SK_BUILD_FOR_ANDROID_NDK) && !defined(SK_BUILD_FOR_ANDROID)
#define SK_BUILD_FOR_ANDROID
#endif
//////////////////////////////////////////////////////////////////////
#if !defined(SK_DEBUG) && !defined(SK_RELEASE)

View File

@ -12,6 +12,10 @@
#if defined(SK_BUILD_FOR_MAC)
#include <AGL/agl.h>
#elif defined(SK_BUILD_FOR_ANDROID)
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#elif defined(SK_BUILD_FOR_UNIX)
#include <X11/Xlib.h>
#include <GL/glx.h>
@ -43,6 +47,10 @@ public:
#elif defined(SK_BUILD_FOR_WIN32)
HDC fOldHDC;
HGLRC fOldHGLRC;
#elif defined(SK_BUILD_FOR_ANDROID)
EGLContext fOldEGLContext;
EGLDisplay fOldDisplay;
EGLSurface fOldSurface;
#endif
};
@ -63,6 +71,10 @@ private:
HDC fDeviceContext;
HGLRC fGlRenderContext;
static ATOM gWC;
#elif defined(SK_BUILD_FOR_ANDROID)
EGLContext fContext;
EGLDisplay fDisplay;
EGLSurface fSurface;
#endif
};

View File

@ -0,0 +1,375 @@
/*
* Copyright 2011 Skia
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrContext.h"
#include "GrGLInterface.h"
#include "SampleApp.h"
#include "SkApplication.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkEvent.h"
#include "SkGpuCanvas.h"
#include "SkWindow.h"
#include <jni.h>
#include "android/AndroidKeyToSkKey.h"
///////////////////////////////////////////
///////////////// Globals /////////////////
///////////////////////////////////////////
struct ActivityGlue {
JNIEnv* m_env;
jweak m_obj;
jmethodID m_setTitle;
jmethodID m_startTimer;
jmethodID m_addToDownloads;
ActivityGlue() {
m_env = NULL;
m_obj = NULL;
m_setTitle = NULL;
m_startTimer = NULL;
m_addToDownloads = NULL;
}
} gActivityGlue;
struct WindowGlue {
jweak m_obj;
jmethodID m_inval;
jmethodID m_queueSkEvent;
WindowGlue() {
m_obj = NULL;
m_inval = NULL;
m_queueSkEvent = NULL;
}
} gWindowGlue;
SampleWindow* gWindow;
///////////////////////////////////////////
///////////// SkOSWindow impl /////////////
///////////////////////////////////////////
void SkOSWindow::onSetTitle(const char title[])
{
if (gActivityGlue.m_env) {
JNIEnv* env = gActivityGlue.m_env;
jstring string = env->NewStringUTF(title);
env->CallVoidMethod(gActivityGlue.m_obj, gActivityGlue.m_setTitle,
string);
env->DeleteLocalRef(string);
}
}
void SkOSWindow::onHandleInval(const SkIRect& rect)
{
if (!gActivityGlue.m_env || !gWindowGlue.m_inval || !gWindowGlue.m_obj) {
return;
}
gActivityGlue.m_env->CallVoidMethod(gWindowGlue.m_obj, gWindowGlue.m_inval);
}
void SkOSWindow::onPDFSaved(const char title[], const char desc[],
const char path[])
{
if (gActivityGlue.m_env) {
JNIEnv* env = gActivityGlue.m_env;
jstring jtitle = env->NewStringUTF(title);
jstring jdesc = env->NewStringUTF(desc);
jstring jpath = env->NewStringUTF(path);
env->CallVoidMethod(gActivityGlue.m_obj, gActivityGlue.m_addToDownloads,
jtitle, jdesc, jpath);
env->DeleteLocalRef(jtitle);
env->DeleteLocalRef(jdesc);
env->DeleteLocalRef(jpath);
}
}
///////////////////////////////////////////
/////////////// SkEvent impl //////////////
///////////////////////////////////////////
void SkEvent::SignalQueueTimer(SkMSec ms)
{
if (!gActivityGlue.m_env || !gActivityGlue.m_startTimer
|| !gActivityGlue.m_obj || !ms) {
return;
}
gActivityGlue.m_env->CallVoidMethod(gActivityGlue.m_obj,
gActivityGlue.m_startTimer, ms);
}
void SkEvent::SignalNonEmptyQueue()
{
if (!gActivityGlue.m_env || !gWindowGlue.m_queueSkEvent
|| !gWindowGlue.m_obj) {
return;
}
gActivityGlue.m_env->CallVoidMethod(gWindowGlue.m_obj,
gWindowGlue.m_queueSkEvent);
}
///////////////////////////////////////////
////////////////// JNI ////////////////////
///////////////////////////////////////////
static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[],
const char signature[])
{
jmethodID m = env->GetMethodID(clazz, name, signature);
if (!m) SkDebugf("Could not find Java method %s\n", name);
return m;
}
extern "C" {
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_draw(
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_init(
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_term(
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_updateSize(
JNIEnv* env, jobject thiz, jint w, jint h);
JNIEXPORT bool JNICALL Java_com_skia_sampleapp_SampleApp_handleKeyDown(
JNIEnv* env, jobject thiz, jint keyCode, jint uni);
JNIEXPORT bool JNICALL Java_com_skia_sampleapp_SampleApp_handleKeyUp(
JNIEnv* env, jobject thiz, jint keyCode);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_handleClick(
JNIEnv* env, jobject thiz, jint owner, jfloat x, jfloat y, jint state);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_createOSWindow(
JNIEnv* env, jobject thiz, jobject jsampleView);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_setZoomCenter(
JNIEnv* env, jobject thiz, jfloat x, jfloat y);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_zoom(
JNIEnv* env, jobject thiz, jfloat factor);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_nextSample(
JNIEnv* env, jobject thiz, jboolean fprevious);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleRendering(
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleSlideshow(
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleFps(
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_processSkEvent(
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_serviceQueueTimer(
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_saveToPdf(
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_postInval(
JNIEnv* env, jobject thiz);
};
JNIEXPORT bool JNICALL Java_com_skia_sampleapp_SampleApp_handleKeyDown(
JNIEnv* env, jobject thiz, jint keyCode, jint uni)
{
bool handled = gWindow->handleKey(AndroidKeycodeToSkKey(keyCode));
handled |= gWindow->handleChar((SkUnichar) uni);
return handled;
}
JNIEXPORT bool JNICALL Java_com_skia_sampleapp_SampleApp_handleKeyUp(JNIEnv* env,
jobject thiz, jint keyCode)
{
return gWindow->handleKeyUp(AndroidKeycodeToSkKey(keyCode));
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_handleClick(JNIEnv* env,
jobject thiz, jint owner, jfloat x, jfloat y, jint jstate)
{
SkView::Click::State state;
switch(jstate) {
case 0: // MotionEvent.ACTION_DOWN
state = SkView::Click::kDown_State;
break;
case 1: // MotionEvent.ACTION_UP
case 3: // MotionEvent.ACTION_CANCEL
state = SkView::Click::kUp_State;
break;
case 2: // MotionEvent.ACTION_MOVE
state = SkView::Click::kMoved_State;
break;
default:
SkDebugf("motion event ignored\n");
return;
}
gWindow->handleClick(x, y, state, (void*) owner);
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_updateSize(JNIEnv* env,
jobject thiz, jint w, jint h)
{
gWindow->resize(w, h);
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_createOSWindow(
JNIEnv* env, jobject thiz, jobject jsampleView)
{
gWindow = new SampleWindow(NULL);
jclass clazz = gActivityGlue.m_env->FindClass(
"com/skia/sampleapp/SampleView");
gWindowGlue.m_obj = gActivityGlue.m_env->NewWeakGlobalRef(jsampleView);
gWindowGlue.m_inval = GetJMethod(gActivityGlue.m_env, clazz,
"requestRender", "()V");
gWindowGlue.m_queueSkEvent = GetJMethod(gActivityGlue.m_env, clazz,
"queueSkEvent", "()V");
gActivityGlue.m_env->DeleteLocalRef(clazz);
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_init(JNIEnv* env,
jobject thiz)
{
gActivityGlue.m_env = env;
jclass clazz = env->FindClass("com/skia/sampleapp/SampleApp");
gActivityGlue.m_obj = env->NewWeakGlobalRef(thiz);
gActivityGlue.m_setTitle = GetJMethod(env, clazz, "setTitle",
"(Ljava/lang/CharSequence;)V");
gActivityGlue.m_addToDownloads = GetJMethod(env, clazz, "addToDownloads",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
gActivityGlue.m_startTimer = GetJMethod(gActivityGlue.m_env, clazz,
"startTimer", "(I)V");
env->DeleteLocalRef(clazz);
application_init();
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_term(JNIEnv* env,
jobject thiz)
{
delete gWindow;
gWindow = NULL;
application_term();
if (gWindowGlue.m_obj) {
env->DeleteWeakGlobalRef(gWindowGlue.m_obj);
gWindowGlue.m_obj = NULL;
}
if (gActivityGlue.m_obj) {
env->DeleteWeakGlobalRef(gActivityGlue.m_obj);
gActivityGlue.m_obj = NULL;
}
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_draw(
JNIEnv* env, jobject thiz)
{
if (!gWindow) return;
gWindow->update(NULL);
// Copy the bitmap to the screen in raster mode
if (!gWindow->drawsToHardware()) {
SkBitmap bitmap = gWindow->getBitmap();
GrContext* context = gWindow->getGrContext();
if (!context) {
context = GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
if (!context || !gWindow->setGrContext(context)) {
return;
}
context->unref();
}
GrRenderTarget* renderTarget;
GrPlatformSurfaceDesc desc;
desc.reset();
desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType;
desc.fWidth = bitmap.width();
desc.fHeight = bitmap.height();
desc.fConfig = kRGBA_8888_GrPixelConfig;
desc.fStencilBits = 8;
GrGLint buffer;
GR_GL_GetIntegerv(GR_GL_FRAMEBUFFER_BINDING, &buffer);
desc.fPlatformRenderTarget = buffer;
renderTarget = static_cast<GrRenderTarget*>(
context->createPlatformSurface(desc));
SkGpuCanvas* gpuCanvas = new SkGpuCanvas(context, renderTarget);
SkDevice* device = gpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
bitmap.width(), bitmap.height(),
false, false);
gpuCanvas->setDevice(device)->unref();
gpuCanvas->drawBitmap(bitmap, 0, 0);
SkSafeUnref(renderTarget);
SkSafeUnref(gpuCanvas);
}
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_setZoomCenter(
JNIEnv* env, jobject thiz, jfloat x, jfloat y)
{
gWindow->setZoomCenter(x, y);
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_zoom(
JNIEnv* env, jobject thiz, jfloat factor)
{
gWindow->changeZoomLevel(factor);
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_nextSample(
JNIEnv* env, jobject thiz, jboolean fprevious)
{
if (fprevious) {
gWindow->previousSample();
} else {
gWindow->nextSample();
}
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleRendering(
JNIEnv* env, jobject thiz)
{
gWindow->toggleRendering();
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleSlideshow(
JNIEnv* env, jobject thiz)
{
gWindow->toggleSlideshow();
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleFps(
JNIEnv* env, jobject thiz)
{
gWindow->toggleFPS();
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_processSkEvent(
JNIEnv* env, jobject thiz)
{
if (SkEvent::ProcessEvent()) {
SkEvent::SignalNonEmptyQueue();
}
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_serviceQueueTimer(
JNIEnv* env, jobject thiz)
{
SkEvent::ServiceQueueTimer();
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_saveToPdf(
JNIEnv* env, jobject thiz)
{
gWindow->saveToPdf();
}
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_postInval(
JNIEnv* env, jobject thiz)
{
gWindow->postInvalDelay();
}

View File

@ -13,10 +13,10 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
const GrGLInterface* GrGLDefaultInterface() {
const GrGLInterface* GrGLCreateNativeInterface() {
static SkAutoTUnref<GrGLInterface> glInterface;
if (!glInterface.get()) {
GrGLInteface* interface = new GrGLInterface;
GrGLInterface* interface = new GrGLInterface;
glInterface.reset(interface);
interface->fBindingsExported = kES2_GrGLBinding;
interface->fActiveTexture = glActiveTexture;

View File

@ -0,0 +1,104 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkNativeGLContext.h"
SkNativeGLContext::AutoContextRestore::AutoContextRestore() {
fOldEGLContext = eglGetCurrentContext();
fOldDisplay = eglGetCurrentDisplay();
fOldSurface = eglGetCurrentSurface(EGL_DRAW);
}
SkNativeGLContext::AutoContextRestore::~AutoContextRestore() {
if (NULL != fOldDisplay) {
eglMakeCurrent(fOldDisplay, fOldSurface, fOldSurface, fOldEGLContext);
}
}
///////////////////////////////////////////////////////////////////////////////
SkNativeGLContext::SkNativeGLContext()
: fContext(EGL_NO_CONTEXT)
, fDisplay(EGL_NO_DISPLAY)
, fSurface(EGL_NO_SURFACE) {
}
SkNativeGLContext::~SkNativeGLContext() {
this->destroyGLContext();
}
void SkNativeGLContext::destroyGLContext() {
if (fDisplay) {
eglMakeCurrent(fDisplay, 0, 0, 0);
if (fContext) {
eglDestroyContext(fDisplay, fContext);
fContext = EGL_NO_CONTEXT;
}
if (fSurface) {
eglDestroySurface(fDisplay, fSurface);
fSurface = EGL_NO_SURFACE;
}
//TODO should we close the display?
fDisplay = EGL_NO_DISPLAY;
}
}
const GrGLInterface* SkNativeGLContext::createGLContext() {
fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
EGLint majorVersion;
EGLint minorVersion;
eglInitialize(fDisplay, &majorVersion, &minorVersion);
EGLint numConfigs;
static const EGLint configAttribs[] = {
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_NONE
};
EGLConfig surfaceConfig;
eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs);
static const EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
fContext = eglCreateContext(fDisplay, surfaceConfig, NULL, contextAttribs);
static const EGLint surfaceAttribs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE
};
fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, surfaceAttribs);
eglMakeCurrent(fDisplay, fSurface, fSurface, fContext);
const GrGLInterface* interface = GrGLCreateNativeInterface();
if (!interface) {
SkDebugf("Failed to create gl interface");
this->destroyGLContext();
return NULL;
}
return interface;
}
void SkNativeGLContext::makeCurrent() const {
if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
SkDebugf("Could not set the context.\n");
}
}

View File

@ -0,0 +1,195 @@
/* libs/graphics/ports/FontHostConfiguration_android.cpp
**
** Copyright 2011, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "FontHostConfiguration_android.h"
#include <expat.h>
#include "SkTDArray.h"
#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.xml"
#define FALLBACK_FONTS_FILE "/system/etc/fallback_fonts.xml"
#define VENDOR_FONTS_FILE "/vendor/etc/fallback_fonts.xml"
// These defines are used to determine the kind of tag that we're currently
// populating with data. We only care about the sibling tags nameset and fileset
// for now.
#define NO_TAG 0
#define NAMESET_TAG 1
#define FILESET_TAG 2
/**
* The FamilyData structure is passed around by the parser so that each handler
* can read these variables that are relevant to the current parsing.
*/
struct FamilyData {
FamilyData(XML_Parser *parserRef, SkTDArray<FontFamily*> &familiesRef) :
parser(parserRef), families(familiesRef), currentTag(NO_TAG) {};
XML_Parser *parser; // The expat parser doing the work
SkTDArray<FontFamily*> &families; // The array that each family is put into as it is parsed
FontFamily *currentFamily; // The current family being created
int currentTag; // A flag to indicate whether we're in nameset/fileset tags
};
/**
* Handler for arbitrary text. This is used to parse the text inside each name
* or file tag. The resulting strings are put into the fNames or fFileNames arrays.
*/
void textHandler(void *data, const char *s, int len) {
FamilyData *familyData = (FamilyData*) data;
// Make sure we're in the right state to store this name information
if (familyData->currentFamily &&
(familyData->currentTag == NAMESET_TAG || familyData->currentTag == FILESET_TAG)) {
// Malloc new buffer to store the string
char *buff;
buff = (char*) malloc((len + 1) * sizeof(char));
strncpy(buff, s, len);
buff[len] = '\0';
switch (familyData->currentTag) {
case NAMESET_TAG:
*(familyData->currentFamily->fNames.append()) = buff;
break;
case FILESET_TAG:
*(familyData->currentFamily->fFileNames.append()) = buff;
break;
default:
// Noop - don't care about any text that's not in the Fonts or Names list
break;
}
}
}
/**
* Handler for the start of a tag. The only tags we expect are family, nameset,
* fileset, name, and file.
*/
void startElementHandler(void *data, const char *tag, const char **atts) {
FamilyData *familyData = (FamilyData*) data;
int len = strlen(tag);
if (strncmp(tag, "family", len)== 0) {
familyData->currentFamily = new FontFamily();
familyData->currentFamily->order = -1;
// The Family tag has an optional "order" attribute with an integer value >= 0
// If this attribute does not exist, the default value is -1
for (int i = 0; atts[i] != NULL; i += 2) {
const char* attribute = atts[i];
const char* valueString = atts[i+1];
int value;
int len = sscanf(valueString, "%d", &value);
if (len > 0) {
familyData->currentFamily->order = value;
}
}
} else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
familyData->currentTag = NAMESET_TAG;
} else if (len == 7 && strncmp(tag, "fileset", len) == 0) {
familyData->currentTag = FILESET_TAG;
} else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) ||
(strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
// If it's a Name, parse the text inside
XML_SetCharacterDataHandler(*familyData->parser, textHandler);
}
}
/**
* Handler for the end of tags. We only care about family, nameset, fileset,
* name, and file.
*/
void endElementHandler(void *data, const char *tag) {
FamilyData *familyData = (FamilyData*) data;
int len = strlen(tag);
if (strncmp(tag, "family", len)== 0) {
// Done parsing a Family - store the created currentFamily in the families array
*familyData->families.append() = familyData->currentFamily;
familyData->currentFamily = NULL;
} else if (len == 7 && strncmp(tag, "nameset", len)== 0) {
familyData->currentTag = NO_TAG;
} else if (len == 7 && strncmp(tag, "fileset", len)== 0) {
familyData->currentTag = NO_TAG;
} else if ((strncmp(tag, "name", len) == 0 && familyData->currentTag == NAMESET_TAG) ||
(strncmp(tag, "file", len) == 0 && familyData->currentTag == FILESET_TAG)) {
// Disable the arbitrary text handler installed to load Name data
XML_SetCharacterDataHandler(*familyData->parser, NULL);
}
}
/**
* This function parses the given filename and stores the results in the given
* families array.
*/
void parseConfigFile(const char *filename, SkTDArray<FontFamily*> &families) {
XML_Parser parser = XML_ParserCreate(NULL);
FamilyData *familyData = new FamilyData(&parser, families);
XML_SetUserData(parser, familyData);
XML_SetElementHandler(parser, startElementHandler, endElementHandler);
FILE *file = fopen(filename, "r");
// Some of the files we attempt to parse (in particular, /vendor/etc/fallback_fonts.xml)
// are optional - failure here is okay because one of these optional files may not exist.
if (file == NULL) {
return;
}
char buffer[512];
bool done = false;
while (!done) {
fgets(buffer, sizeof(buffer), file);
int len = strlen(buffer);
if (feof(file) != 0) {
done = true;
}
XML_Parse(parser, buffer, len, done);
}
}
/**
* Loads data on font families from various expected configuration files. The
* resulting data is returned in the given fontFamilies array.
*/
void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies) {
SkTDArray<FontFamily*> fallbackFonts;
SkTDArray<FontFamily*> vendorFonts;
parseConfigFile(SYSTEM_FONTS_FILE, fontFamilies);
parseConfigFile(FALLBACK_FONTS_FILE, fallbackFonts);
parseConfigFile(VENDOR_FONTS_FILE, vendorFonts);
// This loop inserts the vendor fallback fonts in the correct order in the
// overall fallbacks list.
int currentOrder = -1;
for (int i = 0; i < vendorFonts.count(); ++i) {
FontFamily* family = vendorFonts[i];
int order = family->order;
if (order < 0) {
if (currentOrder < 0) {
// Default case - just add it to the end of the fallback list
*fallbackFonts.append() = family;
} else {
// no order specified on this font, but we're incrementing the order
// based on an earlier order insertion request
*fallbackFonts.insert(currentOrder++) = family;
}
} else {
// Add the font into the fallback list in the specified order. Set
// currentOrder for correct placement of other fonts in the vendor list.
*fallbackFonts.insert(order) = family;
currentOrder = order + 1;
}
}
// Append all fallback fonts to system fonts
for (int i = 0; i < fallbackFonts.count(); ++i) {
*fontFamilies.append() = fallbackFonts[i];
}
}

View File

@ -0,0 +1,42 @@
/* libs/graphics/ports/FontHostConfiguration_android.h
**
** Copyright 2011, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef FONTHOSTCONFIGURATION_ANDROID_H_
#define FONTHOSTCONFIGURATION_ANDROID_H_
#include "SkTDArray.h"
/**
* The FontFamily data structure is created during parsing and handed back to
* Skia to fold into its representation of font families. fNames is the list of
* font names that alias to a font family. fFileNames is the list of font
* filenames for the family. Order is the priority order for the font. This is
* used internally to determine the order in which to place fallback fonts as
* they are read from the configuration files.
*/
struct FontFamily {
SkTDArray<const char*> fNames;
SkTDArray<const char*> fFileNames;
int order;
};
/**
* Parses all system font configuration files and returns the results in an
* array of FontFamily structures.
*/
void getFontFamilies(SkTDArray<FontFamily*> &fontFamilies);
#endif /* FONTHOSTCONFIGURATION_ANDROID_H_ */

View File

@ -322,7 +322,8 @@ static FT_Error getAdvances(FT_Face face, FT_UInt start, FT_UInt count,
}
static bool canEmbed(FT_Face face) {
#ifdef FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING
// The android port of FreeType does not build
#if defined(FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING)
FT_UShort fsType = FT_Get_FSType_Flags(face);
return (fsType & (FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING |
FT_FSTYPE_BITMAP_EMBEDDING_ONLY)) == 0;

View File

@ -1,11 +1,19 @@
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "SkFontHost.h"
#include "SkDescriptor.h"
@ -15,6 +23,7 @@
#include "SkStream.h"
#include "SkThread.h"
#include "SkTSearch.h"
#include "FontHostConfiguration_android.h"
#include <stdio.h>
#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
@ -138,13 +147,17 @@ static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
*/
static FamilyRec* remove_from_family(const SkTypeface* face) {
FamilyRec* family = find_family(face);
SkASSERT(family->fFaces[face->style()] == face);
family->fFaces[face->style()] = NULL;
if (family) {
SkASSERT(family->fFaces[face->style()] == face);
family->fFaces[face->style()] = NULL;
for (int i = 0; i < 4; i++) {
if (family->fFaces[i] != NULL) { // family is non-empty
return NULL;
for (int i = 0; i < 4; i++) {
if (family->fFaces[i] != NULL) { // family is non-empty
return NULL;
}
}
} else {
// SkDebugf("remove_from_family(%p) face not found", face);
}
return family; // return the empty family
}
@ -383,61 +396,80 @@ struct FontInitRec {
const char* const* fNames; // null-terminated list
};
static const char* gSansNames[] = {
"sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
};
static const char* gSerifNames[] = {
"serif", "times", "times new roman", "palatino", "georgia", "baskerville",
"goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
};
static const char* gMonoNames[] = {
"monospace", "courier", "courier new", "monaco", NULL
};
// deliberately empty, but we use the address to identify fallback fonts
static const char* gFBNames[] = { NULL };
/* Fonts must be grouped by family, with the first font in a family having the
list of names (even if that list is empty), and the following members having
null for the list. The names list must be NULL-terminated
*/
static const FontInitRec gSystemFonts[] = {
{ "DroidSans.ttf", gSansNames },
{ "DroidSans-Bold.ttf", NULL },
{ "DroidSerif-Regular.ttf", gSerifNames },
{ "DroidSerif-Bold.ttf", NULL },
{ "DroidSerif-Italic.ttf", NULL },
{ "DroidSerif-BoldItalic.ttf", NULL },
{ "DroidSansMono.ttf", gMonoNames },
/* These are optional, and can be ignored if not found in the file system.
These are appended to gFallbackFonts[] as they are seen, so we list
them in the order we want them to be accessed by NextLogicalFont().
*/
{ "DroidSansArabic.ttf", gFBNames },
{ "DroidSansHebrew.ttf", gFBNames },
{ "DroidSansThai.ttf", gFBNames },
{ "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font
{ "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font
{ "DroidSansJapanese.ttf", gFBNames },
{ "DroidSansFallback.ttf", gFBNames }
};
#define DEFAULT_NAMES gSansNames
/* Fonts are grouped by family, with the first font in a family having the
list of names (even if that list is empty), and the following members having
null for the list. The names list must be NULL-terminated.
*/
static FontInitRec *gSystemFonts;
static size_t gNumSystemFonts = 0;
#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.cfg"
// these globals are assigned (once) by load_system_fonts()
static FamilyRec* gDefaultFamily;
static SkTypeface* gDefaultNormal;
static char** gDefaultNames = NULL;
static uint32_t *gFallbackFonts;
/* This is sized conservatively, assuming that it will never be a size issue.
It will be initialized in load_system_fonts(), and will be filled with the
fontIDs that can be used for fallback consideration, in sorted order (sorted
meaning element[0] should be used first, then element[1], etc. When we hit
a fontID==0 in the array, the list is done, hence our allocation size is
+1 the total number of possible system fonts. Also see NextLogicalFont().
*/
static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
/* Load info from a configuration file that populates the system/fallback font structures
*/
static void load_font_info() {
// load_font_info_xml("/system/etc/system_fonts.xml");
SkTDArray<FontFamily*> fontFamilies;
getFontFamilies(fontFamilies);
SkTDArray<FontInitRec> fontInfo;
bool firstInFamily = false;
for (int i = 0; i < fontFamilies.count(); ++i) {
FontFamily *family = fontFamilies[i];
firstInFamily = true;
for (int j = 0; j < family->fFileNames.count(); ++j) {
FontInitRec fontInfoRecord;
fontInfoRecord.fFileName = family->fFileNames[j];
if (j == 0) {
if (family->fNames.count() == 0) {
// Fallback font
fontInfoRecord.fNames = (char **)gFBNames;
} else {
SkTDArray<const char*> names = family->fNames;
const char **nameList = (const char**)
malloc((names.count() + 1) * sizeof(char*));
if (nameList == NULL) {
// shouldn't get here
break;
}
if (gDefaultNames == NULL) {
gDefaultNames = (char**) nameList;
}
for (int i = 0; i < names.count(); ++i) {
nameList[i] = names[i];
}
nameList[names.count()] = NULL;
fontInfoRecord.fNames = nameList;
}
} else {
fontInfoRecord.fNames = NULL;
}
*fontInfo.append() = fontInfoRecord;
}
}
gNumSystemFonts = fontInfo.count();
gSystemFonts = (FontInitRec*) malloc(gNumSystemFonts * sizeof(FontInitRec));
gFallbackFonts = (uint32_t*) malloc((gNumSystemFonts + 1) * sizeof(uint32_t));
if (gSystemFonts == NULL) {
// shouldn't get here
gNumSystemFonts = 0;
}
for (size_t i = 0; i < gNumSystemFonts; ++i) {
gSystemFonts[i].fFileName = fontInfo[i].fFileName;
gSystemFonts[i].fNames = fontInfo[i].fNames;
}
fontFamilies.deleteAll();
}
/* Called once (ensured by the sentinel check at the beginning of our body).
Initializes all the globals, and register the system fonts.
@ -448,11 +480,13 @@ static void load_system_fonts() {
return;
}
load_font_info();
const FontInitRec* rec = gSystemFonts;
SkTypeface* firstInFamily = NULL;
int fallbackCount = 0;
for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
for (size_t i = 0; i < gNumSystemFonts; i++) {
// if we're the first in a new family, clear firstInFamily
if (rec[i].fNames != NULL) {
firstInFamily = NULL;
@ -490,7 +524,7 @@ static void load_system_fonts() {
const char* const* names = rec[i].fNames;
// record the default family if this is it
if (names == DEFAULT_NAMES) {
if (names == gDefaultNames) {
gDefaultFamily = family;
}
// add the names to map to this family
@ -511,40 +545,85 @@ static void load_system_fonts() {
///////////////////////////////////////////////////////////////////////////////
void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
const char* name = ((FamilyTypeface*)face)->getUniqueString();
// lookup and record if the font is custom (i.e. not a system font)
bool isCustomFont = !((FamilyTypeface*)face)->isSysFont();
stream->writeBool(isCustomFont);
stream->write8((uint8_t)face->style());
if (isCustomFont) {
SkStream* fontStream = ((FamilyTypeface*)face)->openStream();
// store the length of the custom font
uint32_t len = fontStream->getLength();
stream->write32(len);
// store the entire font in the serialized stream
void* fontData = malloc(len);
fontStream->read(fontData, len);
stream->write(fontData, len);
fontStream->unref();
free(fontData);
// SkDebugf("--- fonthost custom serialize %d %d\n", face->style(), len);
if (NULL == name || 0 == *name) {
stream->writePackedUInt(0);
// SkDebugf("--- fonthost serialize null\n");
} else {
uint32_t len = strlen(name);
stream->writePackedUInt(len);
stream->write(name, len);
// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
const char* name = ((FamilyTypeface*)face)->getUniqueString();
stream->write8((uint8_t)face->style());
if (NULL == name || 0 == *name) {
stream->writePackedUInt(0);
// SkDebugf("--- fonthost serialize null\n");
} else {
uint32_t len = strlen(name);
stream->writePackedUInt(len);
stream->write(name, len);
// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
}
}
}
SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
load_system_fonts();
int style = stream->readU8();
// check if the font is a custom or system font
bool isCustomFont = stream->readBool();
int len = stream->readPackedUInt();
if (len > 0) {
SkString str;
str.resize(len);
stream->read(str.writable_str(), len);
if (isCustomFont) {
const FontInitRec* rec = gSystemFonts;
for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
// backup until we hit the fNames
for (int j = i; j >= 0; --j) {
if (rec[j].fNames != NULL) {
return SkFontHost::CreateTypeface(NULL,
rec[j].fNames[0], NULL, 0, (SkTypeface::Style)style);
// read the length of the custom font from the stream
uint32_t len = stream->readU32();
// generate a new stream to store the custom typeface
SkMemoryStream* fontStream = new SkMemoryStream(len);
stream->read((void*)fontStream->getMemoryBase(), len);
SkTypeface* face = CreateTypefaceFromStream(fontStream);
fontStream->unref();
// SkDebugf("--- fonthost custom deserialize %d %d\n", face->style(), len);
return face;
} else {
int style = stream->readU8();
int len = stream->readPackedUInt();
if (len > 0) {
SkString str;
str.resize(len);
stream->read(str.writable_str(), len);
const FontInitRec* rec = gSystemFonts;
for (size_t i = 0; i < gNumSystemFonts; i++) {
if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
// backup until we hit the fNames
for (int j = i; j >= 0; --j) {
if (rec[j].fNames != NULL) {
return SkFontHost::CreateTypeface(NULL,
rec[j].fNames[0], NULL, 0,
(SkTypeface::Style)style);
}
}
}
}
@ -627,6 +706,16 @@ size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
load_system_fonts();
const SkTypeface* origTypeface = find_from_uniqueID(origFontID);
const SkTypeface* currTypeface = find_from_uniqueID(currFontID);
SkASSERT(origTypeface != 0);
SkASSERT(currTypeface != 0);
// Our fallback list always stores the id of the plain in each fallback
// family, so we transform currFontID to its plain equivalent.
currFontID = find_typeface(currTypeface, SkTypeface::kNormal)->uniqueID();
/* First see if fontID is already one of our fallbacks. If so, return
its successor. If fontID is not in our list, then return the first one
in our list. Note: list is zero-terminated, and returning zero means
@ -635,10 +724,17 @@ SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
const uint32_t* list = gFallbackFonts;
for (int i = 0; list[i] != 0; i++) {
if (list[i] == currFontID) {
return list[i+1];
if (list[i+1] == 0)
return 0;
const SkTypeface* nextTypeface = find_from_uniqueID(list[i+1]);
return find_typeface(nextTypeface, origTypeface->style())->uniqueID();
}
}
return list[0];
// If we get here, currFontID was not a fallback, so we start at the
// beginning of our list.
const SkTypeface* firstTypeface = find_from_uniqueID(list[0]);
return find_typeface(firstTypeface, origTypeface->style())->uniqueID();
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -132,7 +132,7 @@ bool SkOSFile::Iter::next(SkString* name, bool getDir)
return fHandle != (HANDLE)~0 && get_the_file(fHandle, name, dataPtr, getDir);
}
#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX)
#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
#if 0
OSStatus FSPathMakeRef (