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:
parent
d0601d2e7d
commit
58629291bc
@ -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"
|
||||
|
@ -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
152
gyp/android_system.gyp
Normal 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',
|
||||
],
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
@ -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',
|
||||
|
@ -136,6 +136,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'
|
||||
}
|
||||
|
||||
|
18
gyp/core.gyp
18
gyp/core.gyp
@ -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': [
|
||||
|
17
gyp/gpu.gyp
17
gyp/gpu.gyp
@ -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',
|
||||
],
|
||||
},
|
||||
}],
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -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': [
|
||||
|
26
gyp/opts.gyp
26
gyp/opts.gyp
@ -35,12 +35,36 @@
|
||||
'-msse2',
|
||||
],
|
||||
}],
|
||||
],
|
||||
[ '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',
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
375
samplecode/SampleApp_android.cpp
Normal file
375
samplecode/SampleApp_android.cpp
Normal 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();
|
||||
}
|
@ -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;
|
104
src/gpu/android/SkNativeGLContext_android.cpp
Normal file
104
src/gpu/android/SkNativeGLContext_android.cpp
Normal 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");
|
||||
}
|
||||
}
|
195
src/ports/FontHostConfiguration_android.cpp
Normal file
195
src/ports/FontHostConfiguration_android.cpp
Normal 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];
|
||||
}
|
||||
}
|
42
src/ports/FontHostConfiguration_android.h
Normal file
42
src/ports/FontHostConfiguration_android.h
Normal 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_ */
|
@ -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;
|
||||
|
@ -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,6 +147,7 @@ static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
|
||||
*/
|
||||
static FamilyRec* remove_from_family(const SkTypeface* face) {
|
||||
FamilyRec* family = find_family(face);
|
||||
if (family) {
|
||||
SkASSERT(family->fFaces[face->style()] == face);
|
||||
family->fFaces[face->style()] = NULL;
|
||||
|
||||
@ -146,6 +156,9 @@ static FamilyRec* remove_from_family(const SkTypeface* face) {
|
||||
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,6 +545,28 @@ static void load_system_fonts() {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
|
||||
// lookup and record if the font is custom (i.e. not a system font)
|
||||
bool isCustomFont = !((FamilyTypeface*)face)->isSysFont();
|
||||
stream->writeBool(isCustomFont);
|
||||
|
||||
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);
|
||||
|
||||
} else {
|
||||
const char* name = ((FamilyTypeface*)face)->getUniqueString();
|
||||
|
||||
stream->write8((uint8_t)face->style());
|
||||
@ -524,11 +580,32 @@ void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
|
||||
stream->write(name, len);
|
||||
// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
|
||||
load_system_fonts();
|
||||
|
||||
// check if the font is a custom or system font
|
||||
bool isCustomFont = stream->readBool();
|
||||
|
||||
if (isCustomFont) {
|
||||
|
||||
// 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();
|
||||
@ -538,13 +615,15 @@ SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
|
||||
stream->read(str.writable_str(), len);
|
||||
|
||||
const FontInitRec* rec = gSystemFonts;
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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 (
|
||||
|
Loading…
Reference in New Issue
Block a user