New Android core
This commit is contained in:
parent
a3ae89313f
commit
a223b511e4
189 changed files with 84 additions and 90804 deletions
18
.gitmodules
vendored
18
.gitmodules
vendored
|
@ -1,18 +0,0 @@
|
|||
[submodule "Osmand-kernel/jpeg/jpeg_library"]
|
||||
path = Osmand-kernel/jpeg/jpeg_library
|
||||
url = https://android.googlesource.com/platform/external/jpeg.git
|
||||
[submodule "Osmand-kernel/skia/skia_library"]
|
||||
path = Osmand-kernel/skia/skia_library
|
||||
url = https://android.googlesource.com/platform/external/skia.git
|
||||
[submodule "Osmand-kernel/png/png_library"]
|
||||
path = Osmand-kernel/png/png_library
|
||||
url = https://android.googlesource.com/platform/external/libpng.git
|
||||
[submodule "Osmand-kernel/freetype/freetype_library"]
|
||||
path = Osmand-kernel/freetype/freetype_library
|
||||
url = https://android.googlesource.com/platform/external/freetype.git
|
||||
[submodule "Osmand-kernel/expat/expat_library"]
|
||||
path = Osmand-kernel/expat/expat_library
|
||||
url = https://android.googlesource.com/platform/external/expat.git
|
||||
[submodule "Osmand-kernel/gif/gif_library"]
|
||||
path = Osmand-kernel/gif/gif_library
|
||||
url = https://android.googlesource.com/platform/external/giflib.git
|
|
@ -1,16 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?fileVersion 4.0.0?>
|
||||
|
||||
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||
<cconfiguration id="com.android.toolchain.gcc.128294115">
|
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.android.toolchain.gcc.128294115" moduleId="org.eclipse.cdt.core.settings" name="Default">
|
||||
<externalSettings/>
|
||||
<extensions>
|
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
</extensions>
|
||||
|
@ -20,32 +15,12 @@
|
|||
<folderInfo id="com.android.toolchain.gcc.128294115.2018451624" name="/" resourcePath="">
|
||||
<toolChain id="com.android.toolchain.gcc.88177390" name="com.android.toolchain.gcc" superClass="com.android.toolchain.gcc">
|
||||
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="com.android.targetPlatform.998053113" name="Android Platform" osList="all" superClass="com.android.targetPlatform"/>
|
||||
<builder arguments="${ANDROID_NDK}/ndk-build" command="sh" enableCleanBuild="false" enabledIncrementalBuild="false" id="com.android.builder.1130188873" incrementalBuildTarget="V=1" keepEnvironmentInBuildfile="false" managedBuildOn="false" superClass="com.android.builder">
|
||||
<builder arguments="${ANDROID_NDK}/ndk-build" command="sh" enableCleanBuild="false" enabledIncrementalBuild="false" id="com.android.builder.1130188873" incrementalBuildTarget="V=1" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Android Builder" superClass="com.android.builder">
|
||||
<outputEntries>
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name="libs"/>
|
||||
</outputEntries>
|
||||
</builder>
|
||||
<tool id="cdt.managedbuild.tool.gnu.archiver.base.2094589046" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
|
||||
<tool id="com.android.tool.compiler.g++.1543637239" name="Android G++" superClass="com.android.tool.compiler.g++">
|
||||
<option id="gnu.cpp.compiler.option.include.paths.757537552" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/sources/cxx-stl/gnu-libstdc++/include"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android/external/skia/include/core"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android/frameworks/base/include"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android/external/skia/include/effects"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/platforms/android-8/arch-arm/usr/include/linux/"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/sources/cxx-stl/system/include"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/sources/cxx-stl/stlport/stlport"/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/OsmAnd/jni/protobuf}""/>
|
||||
</option>
|
||||
<inputType id="com.android.tool.compiler.g++.input.478508689" superClass="com.android.tool.compiler.g++.input"/>
|
||||
</tool>
|
||||
<tool id="com.android.tool.compiler.c.1571517563" name="Android GCC" superClass="com.android.tool.compiler.c">
|
||||
<option id="gnu.c.compiler.option.include.paths.741601891" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/sources/cxx-stl/gnu-libstdc++/include"/>
|
||||
</option>
|
||||
<inputType id="com.android.tool.compiler.c.input.1589735828" superClass="com.android.tool.compiler.c.input"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.linker.base.1072970274" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.1246211237" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
|
||||
<option id="gnu.cpp.link.option.paths.266312846" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths"/>
|
||||
|
@ -58,6 +33,9 @@
|
|||
<tool id="cdt.managedbuild.tool.gnu.assembler.base.160853213" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.2064867964" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||
</tool>
|
||||
<tool id="com.android.gcc.compiler.1578834002" name="Android GCC Compiler" superClass="com.android.gcc.compiler">
|
||||
<inputType id="com.android.gcc.inputType.2131113103" superClass="com.android.gcc.inputType"/>
|
||||
</tool>
|
||||
</toolChain>
|
||||
</folderInfo>
|
||||
<sourceEntries>
|
||||
|
@ -71,8 +49,10 @@
|
|||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<project id="OsmAnd.null.100587230" name="OsmAnd"/>
|
||||
</storageModule>
|
||||
<storageModule moduleId="refreshScope" versionNumber="1">
|
||||
<resource resourceType="PROJECT" workspacePath="/OsmAnd"/>
|
||||
<storageModule moduleId="refreshScope" versionNumber="2">
|
||||
<configuration configurationName="Default">
|
||||
<resource resourceType="PROJECT" workspacePath="/OsmAnd"/>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
|
||||
|
@ -103,4 +83,5 @@
|
|||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
|
||||
</scannerConfigBuildInfo>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||
</cproject>
|
||||
|
|
11
OsmAnd/.settings/org.eclipse.jdt.core.prefs
Executable file
11
OsmAnd/.settings/org.eclipse.jdt.core.prefs
Executable file
|
@ -0,0 +1,11 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
|
@ -1,16 +1,15 @@
|
|||
# Relative definition of kernel makefile
|
||||
OSMAND_MAKEFILES := $(call my-dir)/../../Osmand-kernel/Android.mk
|
||||
OSMAND_MAKEFILES := $(all-subdir-makefiles) $(call all-makefiles-under,$(call my-dir)/../../../../core/targets/android)
|
||||
|
||||
# Protect from previous builds
|
||||
ifneq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
OSMAND_BUILDING_NEON_LIBRARY := false
|
||||
OSMAND_BUILDING_NEON_LIBRARY := false
|
||||
endif
|
||||
|
||||
# OSMAND_FORCE_NEON_SUPPORT is used to force only NEON support on ARMv7a
|
||||
ifdef OSMAND_FORCE_NEON_SUPPORT
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
OSMAND_BUILDING_NEON_LIBRARY := true
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
OSMAND_BUILDING_NEON_LIBRARY := true
|
||||
endif
|
||||
endif
|
||||
|
||||
# By default, include makefiles only once
|
||||
|
@ -19,12 +18,12 @@ include $(OSMAND_MAKEFILES)
|
|||
# If we're not asked not to support NEON and not asked to support only NEON ARMv7a, then
|
||||
# make additional build
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
ifndef OSMAND_SKIP_NEON_SUPPORT
|
||||
ifndef OSMAND_FORCE_NEON_SUPPORT
|
||||
ifndef OSMAND_SKIP_NEON_SUPPORT
|
||||
ifndef OSMAND_FORCE_NEON_SUPPORT
|
||||
|
||||
OSMAND_BUILDING_NEON_LIBRARY := true
|
||||
include $(OSMAND_MAKEFILES)
|
||||
OSMAND_BUILDING_NEON_LIBRARY := true
|
||||
include $(OSMAND_MAKEFILES)
|
||||
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
|
@ -1,24 +1,24 @@
|
|||
APP_STL := stlport_shared
|
||||
APP_STL := gnustl_shared
|
||||
APP_ABI := all
|
||||
APP_CPPFLAGS := -fno-rtti -fno-exceptions
|
||||
APP_CPPFLAGS := -std=c++11 -fno-rtti -fno-exceptions
|
||||
|
||||
ifdef OSMAND_X86_ONLY
|
||||
APP_ABI := x86
|
||||
APP_ABI := x86
|
||||
else
|
||||
ifdef OSMAND_ARM_ONLY
|
||||
APP_ABI := armeabi armeabi-v7a
|
||||
APP_ABI := armeabi armeabi-v7a
|
||||
else
|
||||
ifdef OSMAND_ARMv5_ONLY
|
||||
APP_ABI := armeabi
|
||||
APP_ABI := armeabi
|
||||
endif
|
||||
ifdef OSMAND_ARMv7a_ONLY
|
||||
APP_ABI := armeabi-v7a
|
||||
APP_ABI := armeabi-v7a
|
||||
endif
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
ifndef OSMAND_DEBUG_NATIVE
|
||||
# Force release compilation in release optimizations, even if application is debuggable by manifest
|
||||
APP_OPTIM := release
|
||||
# Force release compilation in release optimizations, even if application is debuggable by manifest
|
||||
APP_OPTIM := release
|
||||
endif
|
22
OsmAnd/jni/cpufeatures_proxy/Android.mk
Executable file
22
OsmAnd/jni/cpufeatures_proxy/Android.mk
Executable file
|
@ -0,0 +1,22 @@
|
|||
# CPU Features library should not be built for newon
|
||||
ifneq ($(OSMAND_BUILDING_NEON_LIBRARY),true)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := cpufeatures_proxy
|
||||
ifneq ($(OSMAND_USE_PREBUILT),true)
|
||||
LOCAL_SRC_FILES := \
|
||||
cpuCheck.cpp
|
||||
LOCAL_STATIC_LIBRARIES := cpufeatures
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
else
|
||||
LOCAL_SRC_FILES := \
|
||||
../lib/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).so
|
||||
LOCAL_STATIC_LIBRARIES := cpufeatures
|
||||
include $(PREBUILT_SHARED_LIBRARY)
|
||||
endif
|
||||
|
||||
$(call import-module,android/cpufeatures)
|
||||
|
||||
endif
|
20
OsmAnd/proguard-project.txt
Executable file
20
OsmAnd/proguard-project.txt
Executable file
|
@ -0,0 +1,20 @@
|
|||
# To enable ProGuard in your project, edit project.properties
|
||||
# to define the proguard.config property as described in that file.
|
||||
#
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
|
@ -28,8 +28,8 @@ public class NativeOsmandLibrary extends NativeLibrary {
|
|||
synchronized (NativeOsmandLibrary.class) {
|
||||
if (!isLoaded()) {
|
||||
try {
|
||||
log.debug("Loading native stlport_shared..."); //$NON-NLS-1$
|
||||
System.loadLibrary("stlport_shared");
|
||||
log.debug("Loading native gnustl_shared..."); //$NON-NLS-1$
|
||||
System.loadLibrary("gnustl_shared");
|
||||
log.debug("Loading native cpufeatures_proxy..."); //$NON-NLS-1$
|
||||
System.loadLibrary("cpufeatures_proxy");
|
||||
if(android.os.Build.VERSION.SDK_INT >= 8) {
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?fileVersion 4.0.0?>
|
||||
|
||||
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
|
||||
<storageModule moduleId="org.eclipse.cdt.core.settings">
|
||||
<cconfiguration id="com.android.toolchain.gcc.128294115">
|
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.android.toolchain.gcc.128294115" moduleId="org.eclipse.cdt.core.settings" name="Default">
|
||||
<externalSettings/>
|
||||
<extensions>
|
||||
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
|
||||
</extensions>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<configuration artifactName="OsmAnd" buildProperties="" description="" id="com.android.toolchain.gcc.128294115" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
|
||||
<folderInfo id="com.android.toolchain.gcc.128294115.2018451624" name="/" resourcePath="">
|
||||
<toolChain id="com.android.toolchain.gcc.88177390" name="com.android.toolchain.gcc" superClass="com.android.toolchain.gcc">
|
||||
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="com.android.targetPlatform.998053113" name="Android Platform" osList="all" superClass="com.android.targetPlatform"/>
|
||||
<builder arguments="${ANDROID_NDK}/ndk-build" command="sh" enableCleanBuild="false" enabledIncrementalBuild="true" id="com.android.builder.1130188873" incrementalBuildTarget="V=1" keepEnvironmentInBuildfile="false" managedBuildOn="false" superClass="com.android.builder">
|
||||
<outputEntries>
|
||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name="libs"/>
|
||||
</outputEntries>
|
||||
</builder>
|
||||
<tool id="cdt.managedbuild.tool.gnu.archiver.base.2094589046" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
|
||||
<tool id="com.android.tool.compiler.g++.1543637239" name="Android G++" superClass="com.android.tool.compiler.g++">
|
||||
<option id="gnu.cpp.compiler.option.include.paths.757537552" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value="/usr/include"/>
|
||||
<listOptionValue builtIn="false" value="/usr/include/linux"/>
|
||||
<listOptionValue builtIn="false" value="/usr/include/i386-linux-gnu"/>
|
||||
<listOptionValue builtIn="false" value="/usr/include/c++/4.6"/>
|
||||
<listOptionValue builtIn="false" value="/usr/include/c++/4.6/i686-linux-gnu"/>
|
||||
<listOptionValue builtIn="false" value="/usr/include/c++/4.6/backward"/>
|
||||
<listOptionValue builtIn="false" value="/usr/include/c++/4.6/tr1"/>
|
||||
<listOptionValue builtIn="false" value="/usr/lib/gcc/i686-linux-gnu/4.6/include/"/>
|
||||
<listOptionValue builtIn="false" value="/usr/lib/jvm/java-6-sun-1.6.0.26/include"/>
|
||||
<listOptionValue builtIn="false" value="/usr/lib/jvm/java-6-sun-1.6.0.26/include/linux"/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Osmand-kernel/protobuf/}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Osmand-kernel/cpufeatures_proxy}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Osmand-kernel/jpeg/jpeg_library}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Osmand-kernel/skia/skia_library}""/>
|
||||
</option>
|
||||
<option id="gnu.cpp.compiler.option.preprocessor.def.1044210753" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
|
||||
<listOptionValue builtIn="false" value="LINUX_BUILD=true"/>
|
||||
</option>
|
||||
<inputType id="com.android.tool.compiler.g++.input.478508689" superClass="com.android.tool.compiler.g++.input"/>
|
||||
</tool>
|
||||
<tool id="com.android.tool.compiler.c.1571517563" name="Android GCC" superClass="com.android.tool.compiler.c">
|
||||
<option id="gnu.c.compiler.option.include.paths.741601891" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths"/>
|
||||
<inputType id="com.android.tool.compiler.c.input.1589735828" superClass="com.android.tool.compiler.c.input"/>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.linker.base.1072970274" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
|
||||
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.1246211237" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
|
||||
<option id="gnu.cpp.link.option.paths.266312846" name="Library search path (-L)" superClass="gnu.cpp.link.option.paths"/>
|
||||
<option id="gnu.cpp.link.option.libs.743028931" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs"/>
|
||||
<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.2067702743" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
|
||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||
</inputType>
|
||||
</tool>
|
||||
<tool id="cdt.managedbuild.tool.gnu.assembler.base.160853213" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.2064867964" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
|
||||
</tool>
|
||||
</toolChain>
|
||||
</folderInfo>
|
||||
<fileInfo id="com.android.toolchain.gcc.128294115.1083085764" name="osmand_nacl.c" rcbsApplicability="disable" resourcePath="osmand_nacl/osmand_nacl.c" toolsToInvoke="cdt.managedbuild.tool.gnu.c.compiler.base.938549815">
|
||||
<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.938549815" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
|
||||
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1970000521" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
|
||||
</tool>
|
||||
</fileInfo>
|
||||
<fileInfo id="com.android.toolchain.gcc.128294115.1197161253" name="common.cpp" rcbsApplicability="disable" resourcePath="osmand/src/common.cpp" toolsToInvoke="com.android.tool.compiler.g++.1543637239.697408162">
|
||||
<tool id="com.android.tool.compiler.g++.1543637239.697408162" name="Android G++" superClass="com.android.tool.compiler.g++.1543637239">
|
||||
<option id="gnu.cpp.compiler.option.include.paths.816070414" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value="/usr/include/linux/"/>
|
||||
<listOptionValue builtIn="false" value="/usr/include"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r7c/sources/cxx-stl/stlport/stlport"/>
|
||||
<listOptionValue builtIn="false" value="/usr/lib/jvm/java-6-sun-1.6.0.26/include"/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Osmand-kernel/protobuf/}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Osmand-kernel/cpufeatures_proxy}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Osmand-kernel/jpeg/jpeg_library}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/Osmand-kernel/skia/skia_library}""/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r7c/platforms/android-3/arch-arm/usr/include"/>
|
||||
<listOptionValue builtIn="false" value="/usr/lib/jvm/java-6-sun-1.6.0.26/include/linux"/>
|
||||
<listOptionValue builtIn="false" value="/usr/lib/gcc/i686-linux-gnu/4.6.3/include"/>
|
||||
</option>
|
||||
<inputType id="com.android.tool.compiler.g++.input.311247229" superClass="com.android.tool.compiler.g++.input"/>
|
||||
</tool>
|
||||
</fileInfo>
|
||||
<sourceEntries>
|
||||
<entry excluding="osmand_nacl/osmand_nacl.c" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
|
||||
</sourceEntries>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
</cconfiguration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<project id="OsmAnd.null.100587230" name="OsmAnd"/>
|
||||
</storageModule>
|
||||
<storageModule moduleId="refreshScope" versionNumber="1">
|
||||
<resource resourceType="PROJECT" workspacePath="/OsmAnd"/>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
|
||||
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
|
||||
<storageModule moduleId="scannerConfiguration">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
<scannerConfigBuildInfo instanceId="com.android.toolchain.gcc.128294115;com.android.toolchain.gcc.128294115.2047610242;com.android.tool.compiler.g++.592567664;com.android.tool.compiler.g++.input.893364443">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="com.android.toolchain.gcc.128294115;com.android.toolchain.gcc.128294115.1197161253;com.android.tool.compiler.g++.1543637239.697408162;com.android.tool.compiler.g++.input.311247229">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="com.android.toolchain.gcc.128294115;com.android.toolchain.gcc.128294115.2018451624;com.android.tool.compiler.g++.1543637239;com.android.tool.compiler.g++.input.478508689">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="com.android.toolchain.gcc.128294115;com.android.toolchain.gcc.128294115.724578803;com.android.tool.compiler.g++.1036636492;com.android.tool.compiler.g++.input.325212280">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="com.android.toolchain.gcc.128294115;com.android.toolchain.gcc.128294115.2047610242;com.android.tool.compiler.c.720867356;com.android.tool.compiler.c.input.1326523466">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="com.android.toolchain.gcc.128294115;com.android.toolchain.gcc.128294115.1436946720;com.android.tool.compiler.c.935108432;com.android.tool.compiler.c.input.446006655">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="com.android.toolchain.gcc.128294115;com.android.toolchain.gcc.128294115.2018451624;com.android.tool.compiler.c.1571517563;com.android.tool.compiler.c.input.1589735828">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="com.android.toolchain.gcc.128294115;com.android.toolchain.gcc.128294115.724578803;com.android.tool.compiler.c.1707562195;com.android.tool.compiler.c.input.1747499585">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="com.android.toolchain.gcc.128294115;com.android.toolchain.gcc.128294115.1083085764;cdt.managedbuild.tool.gnu.c.compiler.base.938549815;cdt.managedbuild.tool.gnu.c.compiler.input.1970000521">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
|
||||
</scannerConfigBuildInfo>
|
||||
<scannerConfigBuildInfo instanceId="com.android.toolchain.gcc.128294115;com.android.toolchain.gcc.128294115.1436946720;com.android.tool.compiler.g++.1800289881;com.android.tool.compiler.g++.input.1857432244">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"/>
|
||||
</scannerConfigBuildInfo>
|
||||
</storageModule>
|
||||
</cproject>
|
2
Osmand-kernel/.gitignore
vendored
2
Osmand-kernel/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
osmand_main*
|
||||
osm_out
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>Osmand-kernel</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -1,66 +0,0 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.cdt.codan.checkers.errnoreturn=Warning
|
||||
org.eclipse.cdt.codan.checkers.errnoreturn.params={implicit\=>false}
|
||||
org.eclipse.cdt.codan.checkers.errreturnvalue=Error
|
||||
org.eclipse.cdt.codan.checkers.errreturnvalue.params={}
|
||||
org.eclipse.cdt.codan.checkers.noreturn=Error
|
||||
org.eclipse.cdt.codan.checkers.noreturn.params={implicit\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={}
|
||||
org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={}
|
||||
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={no_break_comment\=>"no break",last_case_param\=>true,empty_case_param\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={unknown\=>false,exceptions\=>()}
|
||||
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=-Error
|
||||
org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidArguments=-Error
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=-Error
|
||||
org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=-Error
|
||||
org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=-Error
|
||||
org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info
|
||||
org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={pattern\=>"^[a-z]",macro\=>true,exceptions\=>()}
|
||||
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={}
|
||||
org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={}
|
||||
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={}
|
||||
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={macro\=>true,exceptions\=>()}
|
||||
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={paramNot\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={else\=>false,afterelse\=>false}
|
||||
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error
|
||||
org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={macro\=>true}
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={macro\=>true}
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning
|
||||
org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={macro\=>true,exceptions\=>("@(\#)","$Id")}
|
||||
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=-Info
|
||||
org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
|
||||
useParentScope=false
|
|
@ -1,5 +0,0 @@
|
|||
OSMAND_MAKEFILES := $(all-subdir-makefiles)
|
||||
|
||||
# By default, include makefiles only once
|
||||
include $(OSMAND_MAKEFILES)
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
projects := protobuf zlib png skia expat freetype osmand
|
||||
|
||||
.DEFAULT: installr
|
||||
.PHONY: release debug clean installr installd
|
||||
|
||||
installr release debug clean installd:
|
||||
@- $(foreach project,$(projects), \
|
||||
$(MAKE) --directory=./$(project) $@; \
|
||||
)
|
|
@ -1,94 +0,0 @@
|
|||
# Just check if we have everything defined
|
||||
ifeq ($(CC_SOURCE_FILES_EXTS),)
|
||||
CC_SOURCE_FILES_EXTS := c
|
||||
endif
|
||||
ifeq ($(CXX_SOURCE_FILES_EXTS),)
|
||||
CXX_SOURCE_FILES_EXTS := cpp cxx cc
|
||||
endif
|
||||
|
||||
# Target configuration
|
||||
DEBUG_INFO_FORMAT := gdb3
|
||||
ifeq ($(TARGET),windows)
|
||||
DEBUG_INFO_FORMAT := coff
|
||||
endif
|
||||
CXXFLAGS_debug := -g$(DEBUG_INFO_FORMAT) -O0
|
||||
CFLAGS_debug := -g$(DEBUG_INFO_FORMAT) -O0
|
||||
CXXFLAGS_release := -O2
|
||||
CFLAGS_release := -O2
|
||||
|
||||
OUTPUT_DIR_PREFIX = ../lib/$(TARGET)-$(ARCH)
|
||||
BUILD_DIR_PREFIX = ../build/$(TARGET)-$(ARCH)
|
||||
|
||||
OBJECTS_NAMES = $(foreach sourceFilesExt,$(CC_SOURCE_FILES_EXTS), \
|
||||
$(patsubst %.$(sourceFilesExt),%.$(sourceFilesExt).cc.o,$(filter %.$(sourceFilesExt),$(LOCAL_SRC_FILES))) \
|
||||
) $(foreach sourceFilesExt,$(CXX_SOURCE_FILES_EXTS), \
|
||||
$(patsubst %.$(sourceFilesExt),%.$(sourceFilesExt).cxx.o,$(filter %.$(sourceFilesExt),$(LOCAL_SRC_FILES))) \
|
||||
)
|
||||
OBJECTS = $(addprefix obj-$(TARGET)-$(ARCH)/,$(OBJECTS_NAMES))
|
||||
|
||||
# Declare phony targets
|
||||
.PHONY: release debug clean installr installd install-release-$(DYNAMICLIB_EXT) install-debug-$(DYNAMICLIB_EXT) install-release-$(STATICLIB_EXT) install-debug-$(STATICLIB_EXT)
|
||||
|
||||
# Default target
|
||||
.DEFAULT: installr
|
||||
|
||||
# Precious targets
|
||||
.PRECIOUS: build-release/$(LIBNAME).$(LIBTYPE) build-debug/$(LIBNAME).$(LIBTYPE) $(addprefix build-release/,$(OBJECTS)) $(addprefix build-debug/,$(OBJECTS))
|
||||
|
||||
# Route build targets properly
|
||||
installr: $(OUTPUT_DIR_PREFIX)-release/$(LIBNAME).$(LIBTYPE)
|
||||
installd: $(OUTPUT_DIR_PREFIX)-debug/$(LIBNAME).$(LIBTYPE)
|
||||
release: $(BUILD_DIR_PREFIX)-release/$(LIBNAME).$(LIBTYPE)
|
||||
debug: $(BUILD_DIR_PREFIX)-debug/$(LIBNAME).$(LIBTYPE)
|
||||
|
||||
# Clean removes all objects
|
||||
clean:
|
||||
$(RM) -r build-release/obj-$(TARGET)-$(ARCH)
|
||||
$(RM) -r build-debug/obj-$(TARGET)-$(ARCH)
|
||||
$(RM) -r build-release/$(TARGET)-$(ARCH)
|
||||
$(RM) -r build-debug/$(TARGET)-$(ARCH)
|
||||
$(RM) -r $(BUILD_DIR_PREFIX)-release
|
||||
$(RM) -r $(BUILD_DIR_PREFIX)-debug
|
||||
$(RM) $(OUTPUT_DIR_PREFIX)-release/$(LIBNAME).$(LIBTYPE)
|
||||
$(RM) $(OUTPUT_DIR_PREFIX)-debug/$(LIBNAME).$(LIBTYPE)
|
||||
|
||||
# This target copies final output file to output directory
|
||||
$(OUTPUT_DIR_PREFIX)-%/$(LIBNAME).$(DYNAMICLIB_EXT): $(BUILD_DIR_PREFIX)-%/$(LIBNAME).$(LIBTYPE)
|
||||
@mkdir -p $(OUTPUT_DIR_PREFIX)-$*
|
||||
cp $(BUILD_DIR_PREFIX)-$*/$(LIBNAME).$(LIBTYPE) $(OUTPUT_DIR_PREFIX)-$*/$(LIBNAME).$(LIBTYPE)
|
||||
|
||||
$(OUTPUT_DIR_PREFIX)-%/$(LIBNAME).$(STATICLIB_EXT): $(BUILD_DIR_PREFIX)-%/$(LIBNAME).$(LIBTYPE)
|
||||
@echo $@ does not need install
|
||||
|
||||
# Builds source files using CC compiler
|
||||
build-release/obj-$(TARGET)-$(ARCH)/%.cc.o : % $(LOCAL_C_INCLUDES)
|
||||
@mkdir -p `dirname $@`
|
||||
$(CC) -o $@ -c $< $(CFLAGS_release) $(CFLAGS) $(addprefix -I, $(LOCAL_C_INCLUDES)) $(LOCAL_CFLAGS) $(GLOBAL_INCLUDES)
|
||||
build-debug/obj-$(TARGET)-$(ARCH)/%.cc.o : % $(LOCAL_C_INCLUDES)
|
||||
@mkdir -p `dirname $@`
|
||||
$(CC) -o $@ -c $< $(CFLAGS_debug) $(CFLAGS) $(addprefix -I, $(LOCAL_C_INCLUDES)) $(LOCAL_CFLAGS) $(GLOBAL_INCLUDES)
|
||||
|
||||
# Builds source files using CXX compiler
|
||||
build-release/obj-$(TARGET)-$(ARCH)/%.cxx.o : % $(LOCAL_C_INCLUDES)
|
||||
@mkdir -p `dirname $@`
|
||||
$(CXX) -o $@ -c $< $(CXXFLAGS_release) $(CXXFLAGS) $(addprefix -I, $(LOCAL_C_INCLUDES)) $(LOCAL_CFLAGS) $(GLOBAL_INCLUDES)
|
||||
build-debug/obj-$(TARGET)-$(ARCH)/%.cxx.o : % $(LOCAL_C_INCLUDES)
|
||||
@mkdir -p `dirname $@`
|
||||
$(CXX) -o $@ -c $< $(CXXFLAGS_debug) $(CXXFLAGS) $(addprefix -I, $(LOCAL_C_INCLUDES)) $(LOCAL_CFLAGS) $(GLOBAL_INCLUDES)
|
||||
|
||||
# This target assembles static library
|
||||
.SECONDEXPANSION:
|
||||
build-%/$(TARGET)-$(ARCH)/$(LIBNAME).$(STATICLIB_EXT): $$(addprefix build-%/,$(OBJECTS))
|
||||
@mkdir -p `dirname $@`
|
||||
$(AR) rs $@ $(addprefix build-$*/,$(OBJECTS))
|
||||
|
||||
# This target assembles dynamic library
|
||||
.SECONDEXPANSION:
|
||||
build-%/$(TARGET)-$(ARCH)/$(LIBNAME).$(DYNAMICLIB_EXT): $$(addprefix build-%/,$(OBJECTS))
|
||||
@mkdir -p `dirname $@`
|
||||
$(CXX) $(DYNAMICLIB_FLAGS) -o $@ $(addprefix build-$*/,$(OBJECTS)) $(LDFLAGS) -L$(BUILD_DIR_PREFIX)-$* $(LDLIBS)
|
||||
|
||||
# This is for copying binary files to build directory
|
||||
$(BUILD_DIR_PREFIX)-%/$(LIBNAME).$(LIBTYPE): build-%/$(TARGET)-$(ARCH)/$(LIBNAME).$(LIBTYPE)
|
||||
@mkdir -p $(BUILD_DIR_PREFIX)-$*
|
||||
cp build-$*/$(TARGET)-$(ARCH)/$(LIBNAME).$(LIBTYPE) $(BUILD_DIR_PREFIX)-$*/$(LIBNAME).$(LIBTYPE)
|
|
@ -1,159 +0,0 @@
|
|||
# Autodetermine target if not set
|
||||
ifeq ($(TARGET),)
|
||||
ifeq ($(shell uname),Darwin)
|
||||
TARGET := darwin
|
||||
else ifeq ($(shell uname),Linux)
|
||||
TARGET := linux
|
||||
else ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
|
||||
TARGET := windows
|
||||
else ifeq ($(findstring MINGW,$(shell uname)),MINGW)
|
||||
TARGET := windows
|
||||
endif
|
||||
endif
|
||||
|
||||
############################################
|
||||
# Google NaCl target
|
||||
ifeq ($(TARGET),nacl)
|
||||
ifndef NACL_SDK_ROOT
|
||||
$(error Set NACL_SDK_ROOT environment variable)
|
||||
endif
|
||||
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
|
||||
NACL_SDK_ROOT := $(shell cygpath -u "$(NACL_SDK_ROOT)")
|
||||
endif
|
||||
|
||||
OSNAME := $(shell python $(NACL_SDK_ROOT)/tools/getos.py)
|
||||
NACL_TOOLCHAIN := $(abspath $(NACL_SDK_ROOT)/toolchain/$(OSNAME)_x86_newlib)
|
||||
CXX := $(NACL_TOOLCHAIN)/bin/i686-nacl-g++
|
||||
CC := $(NACL_TOOLCHAIN)/bin/i686-nacl-gcc
|
||||
AR := $(NACL_TOOLCHAIN)/bin/i686-nacl-ar
|
||||
STATICLIB_EXT := a
|
||||
DYNAMICLIB_EXT := nexe
|
||||
LIBRARY_PREFIX := lib
|
||||
LDLIBS += -lppapi_cpp -lppapi
|
||||
GLOBAL_INCLUDES := -I../zlib/zlib_library -I$(NACL_TOOLCHAIN)/i686-nacl/usr/include
|
||||
ZLIB_BUILD := defined
|
||||
CFLAGS += -D__int64="long long"
|
||||
CXXFLAGS += -D__int64="long long" -std=gnu++0x
|
||||
DYNAMICLIB_FLAGS := -shared
|
||||
############################################
|
||||
# MacOSX/Darwin target
|
||||
else ifeq ($(TARGET),darwin)
|
||||
MACOSX_TOOLCHAIN_ROOT := /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer
|
||||
MACOSX_SDK := $(IOS_TOOLCHAIN_ROOT)/SDKs/MacOSX10.6.sdk/
|
||||
ifeq ($(JAVA_HOME),)
|
||||
JAVA_HOME = /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers
|
||||
endif
|
||||
|
||||
# Skia on Darwin supports only i386
|
||||
ARCH := i386
|
||||
CXXFLAGS += -arch $(ARCH)
|
||||
CFLAGS += -arch $(ARCH)
|
||||
|
||||
CXX := /usr/bin/g++
|
||||
CC := /usr/bin/gcc
|
||||
AR := /usr/bin/ar
|
||||
GLOBAL_INCLUDES := -I../zlib/zlib_library
|
||||
ZLIB_BUILD := defined
|
||||
STATICLIB_EXT := a
|
||||
DYNAMICLIB_EXT := dylib
|
||||
LIBRARY_PREFIX := lib
|
||||
DYNAMICLIB_FLAGS := -dynamiclib
|
||||
############################################
|
||||
# iOS target
|
||||
else ifeq ($(TARGET),ios)
|
||||
IOS_TOOLCHAIN_ROOT := /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer
|
||||
IOS_SDK := $(IOS_TOOLCHAIN_ROOT)/SDKs/iPhoneOS5.1.sdk/
|
||||
ifeq ($(ARCH),)
|
||||
ARCH := armv6
|
||||
endif
|
||||
|
||||
CXX := $(IOS_TOOLCHAIN_ROOT)/usr/bin/arm-apple-darwin10-llvm-g++-4.2
|
||||
CC := $(IOS_TOOLCHAIN_ROOT)/usr/bin/arm-apple-darwin10-llvm-gcc-4.2
|
||||
AR := $(IOS_TOOLCHAIN_ROOT)/usr/bin/ar
|
||||
GLOBAL_INCLUDES := -I../zlib/zlib_library
|
||||
ZLIB_BUILD := defined
|
||||
STATICLIB_EXT := a
|
||||
DYNAMICLIB_EXT := dylib
|
||||
LIBRARY_PREFIX := lib
|
||||
CXXFLAGS += -isysroot $(IOS_SDK)
|
||||
CFLAGS += -isysroot $(IOS_SDK)
|
||||
DYNAMICLIB_FLAGS := -dynamiclib
|
||||
LDFLAGS := # empty
|
||||
# -arch armv6
|
||||
############################################
|
||||
### EVERYTHING ELSE REQUIRES JAVA_HOME #####
|
||||
else
|
||||
|
||||
# Just don't ask
|
||||
ifndef JAVA_HOME
|
||||
$(error Set JAVA_HOME environment variable)
|
||||
endif
|
||||
|
||||
############################################
|
||||
# Windows via MinGW/Linux and MinGW/Cygwin target
|
||||
ifeq ($(TARGET),windows)
|
||||
CXX := i686-w64-mingw32-g++
|
||||
CC := i686-w64-mingw32-gcc
|
||||
AR := i686-w64-mingw32-ar
|
||||
GLOBAL_INCLUDES := -I../zlib/zlib_library
|
||||
ZLIB_BUILD := defined
|
||||
STATICLIB_EXT := lib
|
||||
DYNAMICLIB_EXT := dll
|
||||
LIBRARY_PREFIX := # empty
|
||||
LDFLAGS += -Wl,--kill-at -static-libstdc++ -static-libgcc
|
||||
CFLAGS += # empty
|
||||
CXXFLAGS += -std=gnu++0x
|
||||
DYNAMICLIB_FLAGS := -shared
|
||||
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
|
||||
# Latest MinGW compiler under Cygwin needs this
|
||||
CFLAGS += -D__int64="long long"
|
||||
CXXFLAGS += -D__int64="long long"
|
||||
endif
|
||||
###########################################
|
||||
# Default target
|
||||
else
|
||||
STATICLIB_EXT := a
|
||||
DYNAMICLIB_EXT := so
|
||||
LIBRARY_PREFIX := lib
|
||||
ZLIB_BUILD := defined
|
||||
DYNAMICLIB_FLAGS := -shared -Wl,--dynamic-list-cpp-new
|
||||
CFLAGS += # empty
|
||||
CXXFLAGS += -std=gnu++0x
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
|
||||
############################################
|
||||
# CPU architectures support
|
||||
|
||||
# Make default definitions
|
||||
ifeq ($(ARCH),)
|
||||
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
|
||||
# Cygwin returns 'unknown'
|
||||
ARCH := i386
|
||||
else
|
||||
ARCH := $(shell uname -i)
|
||||
ifeq ($(ARCH),unknown)
|
||||
ARCH := $(shell uname -m)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# Modify compiler flags
|
||||
ifeq ($(ARCH),i386)
|
||||
CFLAGS += -m32 -fPIC
|
||||
CXXFLAGS += -m32 -fPIC
|
||||
LDFLAGS += -m32 -fPIC
|
||||
else ifeq ($(ARCH),x86_64)
|
||||
CFLAGS += -m64 -fPIC
|
||||
CXXFLAGS += -m64 -fPIC
|
||||
LDFLAGS += -m64 -fPIC
|
||||
else ifeq ($(ARCH),i686)
|
||||
CFLAGS += -m64 -fPIC
|
||||
CXXFLAGS += -m64 -fPIC
|
||||
LDFLAGS += -m64 -fPIC
|
||||
else ifeq ($(ARCH),armv6)
|
||||
else
|
||||
$(error Undefined ARCH $(ARCH))
|
||||
endif
|
2
Osmand-kernel/build/.gitignore
vendored
2
Osmand-kernel/build/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -1,4 +0,0 @@
|
|||
chmod +x zlib/configure.sh
|
||||
cd zlib
|
||||
./configure.sh
|
||||
cd ..
|
|
@ -1,25 +0,0 @@
|
|||
# Do not build for NEON
|
||||
ifneq ($(OSMAND_BUILDING_NEON_LIBRARY),true)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
# Name of the local module
|
||||
LOCAL_MODULE := cpufeatures_proxy
|
||||
|
||||
ifneq ($(OSMAND_USE_PREBUILT),true)
|
||||
LOCAL_SRC_FILES := \
|
||||
cpuCheck.cpp
|
||||
LOCAL_STATIC_LIBRARIES := cpufeatures
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
else
|
||||
LOCAL_SRC_FILES := \
|
||||
../lib/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).so
|
||||
LOCAL_STATIC_LIBRARIES := cpufeatures
|
||||
include $(PREBUILT_SHARED_LIBRARY)
|
||||
endif
|
||||
|
||||
$(call import-module,android/cpufeatures)
|
||||
|
||||
endif
|
1
Osmand-kernel/expat/.gitignore
vendored
1
Osmand-kernel/expat/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
build-*
|
|
@ -1,23 +0,0 @@
|
|||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
include $(LOCAL_PATH)/Common.mk
|
||||
LOCAL_CFLAGS += -fPIC
|
||||
|
||||
ifneq ($(OSMAND_BUILDING_NEON_LIBRARY),true)
|
||||
LOCAL_MODULE := expat_static
|
||||
else
|
||||
LOCAL_MODULE := expat_static_neon
|
||||
LOCAL_ARM_NEON := true
|
||||
endif
|
||||
|
||||
|
||||
ifneq ($(OSMAND_USE_PREBUILT),true)
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
else
|
||||
LOCAL_SRC_FILES := \
|
||||
../lib/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
endif
|
|
@ -1,14 +0,0 @@
|
|||
OSMAND_EXPAT_LOC := ./expat_library
|
||||
OSMAND_EXPAT_ABS := $(LOCAL_PATH)/expat_library
|
||||
|
||||
# Include paths
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(OSMAND_EXPAT_ABS) \
|
||||
$(OSMAND_EXPAT_ABS)/lib
|
||||
|
||||
LOCAL_CFLAGS += -Wall -Wmissing-prototypes -Wstrict-prototypes -fexceptions -DHAVE_EXPAT_CONFIG_H
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(OSMAND_EXPAT_LOC)/lib/xmlparse.c \
|
||||
$(OSMAND_EXPAT_LOC)/lib/xmlrole.c \
|
||||
$(OSMAND_EXPAT_LOC)/lib/xmltok.c
|
|
@ -1,13 +0,0 @@
|
|||
# Include tools definitions
|
||||
include ../Makefile.vars
|
||||
|
||||
# Include project files
|
||||
LOCAL_PATH = .
|
||||
include Common.mk
|
||||
|
||||
# Set library name
|
||||
LIBNAME = $(LIBRARY_PREFIX)expat
|
||||
LIBTYPE = $(STATICLIB_EXT)
|
||||
|
||||
# Finally, include generic rules
|
||||
include ../Makefile.rules
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 28304159f2fea1f702929883c634e52755d6e74b
|
1
Osmand-kernel/freetype/.gitignore
vendored
1
Osmand-kernel/freetype/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
build-*
|
|
@ -1,26 +0,0 @@
|
|||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
include $(LOCAL_PATH)/Common.mk
|
||||
LOCAL_CFLAGS += -fPIC
|
||||
|
||||
# compile in ARM mode, since the glyph loader/renderer is a hotspot
|
||||
# when loading complex pages in the browser
|
||||
#
|
||||
LOCAL_ARM_MODE := arm
|
||||
|
||||
ifneq ($(OSMAND_BUILDING_NEON_LIBRARY),true)
|
||||
LOCAL_MODULE := ft2_static
|
||||
else
|
||||
LOCAL_MODULE := ft2_static_neon
|
||||
LOCAL_ARM_NEON := true
|
||||
endif
|
||||
|
||||
ifneq ($(OSMAND_USE_PREBUILT),true)
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
else
|
||||
LOCAL_SRC_FILES := \
|
||||
../lib/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
endif
|
|
@ -1,40 +0,0 @@
|
|||
OSMAND_FREETYPE_LOC := ./freetype_library
|
||||
|
||||
OSMAND_FREETYPE_ABS := $(LOCAL_PATH)/freetype_library
|
||||
|
||||
LOCAL_SRC_FILES:= \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/ftbbox.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/ftbitmap.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/ftfstype.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/ftglyph.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/ftlcdfil.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/ftstroke.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/fttype1.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/ftxf86.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/ftbase.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/ftsystem.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/ftinit.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/base/ftgasp.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/raster/raster.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/sfnt/sfnt.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/smooth/smooth.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/autofit/autofit.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/truetype/truetype.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/cff/cff.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/psnames/psnames.c \
|
||||
$(OSMAND_FREETYPE_LOC)/src/pshinter/pshinter.c
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(OSMAND_FREETYPE_ABS)/builds \
|
||||
$(OSMAND_FREETYPE_ABS)/include
|
||||
|
||||
LOCAL_CFLAGS += -W -Wall
|
||||
LOCAL_CFLAGS += "-DDARWIN_NO_CARBON"
|
||||
LOCAL_CFLAGS += "-DFT2_BUILD_LIBRARY"
|
||||
|
||||
# the following is for testing only, and should not be used in final builds
|
||||
# of the product
|
||||
#LOCAL_CFLAGS += "-DTT_CONFIG_OPTION_BYTECODE_INTERPRETER"
|
||||
|
||||
LOCAL_CFLAGS += -O2
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
# Include tools definitions
|
||||
include ../Makefile.vars
|
||||
|
||||
# Include project files
|
||||
LOCAL_PATH = .
|
||||
include Common.mk
|
||||
|
||||
# Set library name
|
||||
LIBNAME = $(LIBRARY_PREFIX)ft2
|
||||
LIBTYPE = $(STATICLIB_EXT)
|
||||
|
||||
# Finally, include generic rules
|
||||
include ../Makefile.rules
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 15321e16a085b9b5c85cf029aee86bf57b2e65c1
|
|
@ -1,35 +0,0 @@
|
|||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
ifeq ($(OSMAND_GIF_LOC),)
|
||||
OSMAND_GIF_LOC := ./gif_library
|
||||
endif
|
||||
ifeq ($(OSMAND_GIF_ABS),)
|
||||
OSMAND_GIF_ABS := $(LOCAL_PATH)/gif_library
|
||||
endif
|
||||
|
||||
ifneq ($(OSMAND_BUILDING_NEON_LIBRARY),true)
|
||||
LOCAL_MODULE := gif
|
||||
else
|
||||
LOCAL_MODULE := gif_neon
|
||||
endif
|
||||
|
||||
ifneq ($(OSMAND_USE_PREBUILT),true)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(OSMAND_GIF_LOC)/dgif_lib.c \
|
||||
$(OSMAND_GIF_LOC)/gifalloc.c \
|
||||
$(OSMAND_GIF_LOC)/gif_err.c
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(OSMAND_GIF_ABS)
|
||||
|
||||
LOCAL_CFLAGS += -Wno-format -DHAVE_CONFIG_H
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
else
|
||||
LOCAL_SRC_FILES := \
|
||||
../lib/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
endif
|
|
@ -1 +0,0 @@
|
|||
Subproject commit b2597268aef084202a8c349d1cc072c03c6e22eb
|
|
@ -1,91 +0,0 @@
|
|||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_ARM_MODE := arm
|
||||
|
||||
ifeq ($(OSMAND_JPEG_LOC),)
|
||||
OSMAND_JPEG_LOC := ./jpeg_library
|
||||
endif
|
||||
ifeq ($(OSMAND_JPEG_ABS),)
|
||||
OSMAND_JPEG_ABS := $(LOCAL_PATH)/jpeg_library
|
||||
endif
|
||||
|
||||
ifneq ($(OSMAND_BUILDING_NEON_LIBRARY),true)
|
||||
LOCAL_MODULE := jpeg
|
||||
else
|
||||
LOCAL_MODULE := jpeg_neon
|
||||
endif
|
||||
|
||||
ifneq ($(OSMAND_USE_PREBUILT),true)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(OSMAND_JPEG_LOC)/jcapimin.c \
|
||||
$(OSMAND_JPEG_LOC)/jcapistd.c \
|
||||
$(OSMAND_JPEG_LOC)/jccoefct.c \
|
||||
$(OSMAND_JPEG_LOC)/jccolor.c \
|
||||
$(OSMAND_JPEG_LOC)/jcdctmgr.c \
|
||||
$(OSMAND_JPEG_LOC)/jchuff.c \
|
||||
$(OSMAND_JPEG_LOC)/jcinit.c \
|
||||
$(OSMAND_JPEG_LOC)/jcmainct.c \
|
||||
$(OSMAND_JPEG_LOC)/jcmarker.c \
|
||||
$(OSMAND_JPEG_LOC)/jcmaster.c \
|
||||
$(OSMAND_JPEG_LOC)/jcomapi.c \
|
||||
$(OSMAND_JPEG_LOC)/jcparam.c \
|
||||
$(OSMAND_JPEG_LOC)/jcphuff.c \
|
||||
$(OSMAND_JPEG_LOC)/jcprepct.c \
|
||||
$(OSMAND_JPEG_LOC)/jcsample.c \
|
||||
$(OSMAND_JPEG_LOC)/jctrans.c \
|
||||
$(OSMAND_JPEG_LOC)/jdapimin.c \
|
||||
$(OSMAND_JPEG_LOC)/jdapistd.c \
|
||||
$(OSMAND_JPEG_LOC)/jdatadst.c \
|
||||
$(OSMAND_JPEG_LOC)/jdatasrc.c \
|
||||
$(OSMAND_JPEG_LOC)/jdcoefct.c \
|
||||
$(OSMAND_JPEG_LOC)/jdcolor.c \
|
||||
$(OSMAND_JPEG_LOC)/jddctmgr.c \
|
||||
$(OSMAND_JPEG_LOC)/jdhuff.c \
|
||||
$(OSMAND_JPEG_LOC)/jdinput.c \
|
||||
$(OSMAND_JPEG_LOC)/jdmainct.c \
|
||||
$(OSMAND_JPEG_LOC)/jdmarker.c \
|
||||
$(OSMAND_JPEG_LOC)/jdmaster.c \
|
||||
$(OSMAND_JPEG_LOC)/jdmerge.c \
|
||||
$(OSMAND_JPEG_LOC)/jdphuff.c \
|
||||
$(OSMAND_JPEG_LOC)/jdpostct.c \
|
||||
$(OSMAND_JPEG_LOC)/jdsample.c \
|
||||
$(OSMAND_JPEG_LOC)/jdtrans.c \
|
||||
$(OSMAND_JPEG_LOC)/jerror.c \
|
||||
$(OSMAND_JPEG_LOC)/jfdctflt.c \
|
||||
$(OSMAND_JPEG_LOC)/jfdctfst.c \
|
||||
$(OSMAND_JPEG_LOC)/jfdctint.c \
|
||||
$(OSMAND_JPEG_LOC)/jidctflt.c \
|
||||
$(OSMAND_JPEG_LOC)/jidctfst.c \
|
||||
$(OSMAND_JPEG_LOC)/jidctint.c \
|
||||
$(OSMAND_JPEG_LOC)/jidctred.c \
|
||||
$(OSMAND_JPEG_LOC)/jquant1.c \
|
||||
$(OSMAND_JPEG_LOC)/jquant2.c \
|
||||
$(OSMAND_JPEG_LOC)/jutils.c \
|
||||
$(OSMAND_JPEG_LOC)/jmemmgr.c \
|
||||
$(OSMAND_JPEG_LOC)/armv6_idct.S
|
||||
|
||||
# the original android memory manager.
|
||||
# use sdcard as libjpeg decoder's backing store
|
||||
LOCAL_SRC_FILES += \
|
||||
$(OSMAND_JPEG_LOC)/jmem-android.c
|
||||
|
||||
LOCAL_CFLAGS += -DAVOID_TABLES
|
||||
LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays
|
||||
|
||||
# enable tile based decode
|
||||
LOCAL_CFLAGS += -DANDROID_TILE_BASED_DECODE
|
||||
|
||||
# enable armv6 idct assembly
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
LOCAL_CFLAGS += -DANDROID_ARMV6_IDCT
|
||||
endif
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
else
|
||||
LOCAL_SRC_FILES := \
|
||||
../lib/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
endif
|
|
@ -1 +0,0 @@
|
|||
Subproject commit d4fad7f50f79626455d88523207e05b868819cd8
|
2
Osmand-kernel/lib/.gitignore
vendored
2
Osmand-kernel/lib/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
*
|
||||
!.gitignore
|
1
Osmand-kernel/osmand/.gitignore
vendored
1
Osmand-kernel/osmand/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
build-*
|
|
@ -1,48 +0,0 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
include $(LOCAL_PATH)/Common.mk
|
||||
LOCAL_CFLAGS += -fPIC
|
||||
|
||||
# Name of the local module
|
||||
ifneq ($(OSMAND_BUILDING_NEON_LIBRARY),true)
|
||||
LOCAL_MODULE := osmand
|
||||
else
|
||||
LOCAL_MODULE := osmand_neon
|
||||
LOCAL_ARM_NEON := true
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += src/java_wrap.cpp
|
||||
|
||||
LOCAL_CFLAGS := \
|
||||
-DGOOGLE_PROTOBUF_NO_RTTI \
|
||||
-DANDROID_BUILD \
|
||||
-DSK_BUILD_FOR_ANDROID \
|
||||
-DSK_BUILD_FOR_ANDROID_NDK \
|
||||
-DSK_ALLOW_STATIC_GLOBAL_INITIALIZERS=0 \
|
||||
-DSK_RELEASE \
|
||||
-DGR_RELEASE=1
|
||||
|
||||
ifneq ($(LOCAL_ARM_NEON),true)
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
proto \
|
||||
libjpeg \
|
||||
libft2_static \
|
||||
libpng \
|
||||
libgif \
|
||||
libexpat_static
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := skia
|
||||
else
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
proto_neon \
|
||||
libjpeg_neon \
|
||||
libft2_static_neon \
|
||||
libpng_neon \
|
||||
libgif_neon \
|
||||
libexpat_static_neon
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := skia_neon
|
||||
endif
|
||||
|
||||
LOCAL_LDLIBS := -lz -llog -ldl
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
|
@ -1,31 +0,0 @@
|
|||
PROTOBUF := $(LOCAL_PATH)/../protobuf
|
||||
OSMAND_SKIA_ABS := $(LOCAL_PATH)/../skia/skia_library
|
||||
|
||||
# Include paths
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/src \
|
||||
$(PROTOBUF) \
|
||||
$(LOCAL_PATH)/../skia \
|
||||
$(LOCAL_PATH)/../expat/expat_library/lib \
|
||||
$(OSMAND_SKIA_ABS)/include/core \
|
||||
$(OSMAND_SKIA_ABS)/include/images \
|
||||
$(OSMAND_SKIA_ABS)/include/utils \
|
||||
$(OSMAND_SKIA_ABS)/include/config \
|
||||
$(OSMAND_SKIA_ABS)/include/effects \
|
||||
$(OSMAND_SKIA_ABS)/include/utils/android \
|
||||
$(OSMAND_SKIA_ABS)/src/core
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
src/osmand_log.cpp \
|
||||
src/common.cpp \
|
||||
src/mapObjects.cpp \
|
||||
src/multipolygons.cpp \
|
||||
src/renderRules.cpp \
|
||||
src/rendering.cpp \
|
||||
src/binaryRead.cpp \
|
||||
src/binaryRoutePlanner.cpp \
|
||||
src/proto/osmand_index.pb.cpp
|
||||
|
||||
ifdef OSMAND_PROFILE_NATIVE_OPERATIONS
|
||||
LOCAL_CFLAGS += \
|
||||
-DPROFILE_NATIVE_OPERATIONS
|
||||
endif
|
|
@ -1,90 +0,0 @@
|
|||
# Include tools definitions
|
||||
include ../Makefile.vars
|
||||
|
||||
# Include project files
|
||||
LOCAL_PATH = .
|
||||
include Common.mk
|
||||
|
||||
OSMAND_FLAGS = \
|
||||
-DGOOGLE_PROTOBUF_NO_RTTI \
|
||||
-DSK_ALLOW_STATIC_GLOBAL_INITIALIZERS=0 \
|
||||
-DSK_RELEASE \
|
||||
-DGR_RELEASE=1
|
||||
OSMAND_FLAGS_WINDOWS = \
|
||||
-DSK_BUILD_FOR_WIN32 \
|
||||
-DMINGW_HAS_SECURE_API \
|
||||
-DSkUserConfig_DEFINED \
|
||||
-DPICTURE_VERSION_ICS=1 \
|
||||
-DPICTURE_VERSION_JB=2 \
|
||||
-DSK_SCALAR_IS_FLOAT \
|
||||
-DSK_CAN_USE_FLOAT \
|
||||
-DSK_CPU_LENDIAN
|
||||
OSMAND_FLAGS_MAC = \
|
||||
-DSK_BUILD_FOR_MAC \
|
||||
-DSK_USE_CORETEXT \
|
||||
-DSkUserConfig_DEFINED \
|
||||
-DPICTURE_VERSION_ICS=1 \
|
||||
-DPICTURE_VERSION_JB=2 \
|
||||
-DSK_SCALAR_IS_FLOAT \
|
||||
-DSK_CAN_USE_FLOAT \
|
||||
-DSK_CPU_LENDIAN
|
||||
|
||||
LIBNAME = $(LIBRARY_PREFIX)osmand
|
||||
LIBTYPE = $(DYNAMICLIB_EXT)
|
||||
ifeq ($(TARGET),darwin)
|
||||
LDLIBS += --whole-archive -lskia --no-whole-archive -lproto -lft2 -lexpat -lpng -lz
|
||||
else
|
||||
LDLIBS += -Wl,--whole-archive -lskia -Wl,--no-whole-archive -lproto -lft2 -lexpat -lpng -lz
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),windows)
|
||||
LDLIBS += -lwinmm -lgdi32 -lusp10
|
||||
OSMAND_FLAGS += $(OSMAND_FLAGS_WINDOWS)
|
||||
else ifeq ($(TARGET),darwin)
|
||||
OSMAND_FLAGS += $(OSMAND_FLAGS_MAC)
|
||||
LDLIBS += -framework CoreText -lpthread
|
||||
else ifeq ($(TARGET),nacl)
|
||||
LDLIBS += -lpthread
|
||||
else
|
||||
LDLIBS += -lrt -lpthread
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),nacl)
|
||||
OSMAND_FLAGS += \
|
||||
-DRT_NOT_SUPPORTED
|
||||
LOCAL_SRC_FILES += \
|
||||
src/osmand_nacl.cpp
|
||||
else ifeq ($(TARGET),darwin)
|
||||
LOCAL_SRC_FILES += \
|
||||
src/java_wrap.cpp
|
||||
|
||||
OSMAND_FLAGS += -I"$(JAVA_HOME)"
|
||||
else
|
||||
LOCAL_SRC_FILES += \
|
||||
src/java_wrap.cpp
|
||||
|
||||
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
|
||||
FIXED_JAVA_HOME := $(shell cygpath -u "$(JAVA_HOME)")
|
||||
else
|
||||
FIXED_JAVA_HOME := $(JAVA_HOME)
|
||||
endif
|
||||
ifeq ($(JAVA_OS),)
|
||||
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
|
||||
JAVA_OS := win32
|
||||
endif
|
||||
ifeq ($(findstring MINGW,$(shell uname)),MINGW)
|
||||
JAVA_OS := win32
|
||||
endif
|
||||
endif
|
||||
ifeq ($(JAVA_OS),)
|
||||
JAVA_OS := linux
|
||||
endif
|
||||
OSMAND_FLAGS += -c -I"$(FIXED_JAVA_HOME)/include" -I"$(FIXED_JAVA_HOME)/include/$(JAVA_OS)"
|
||||
|
||||
endif
|
||||
|
||||
CFLAGS += $(OSMAND_FLAGS)
|
||||
CXXFLAGS += $(OSMAND_FLAGS)
|
||||
|
||||
# Finally, include generic rules
|
||||
include ../Makefile.rules
|
|
@ -1,50 +0,0 @@
|
|||
THIS_MAKE:=$(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
LIBNAME:=osmand
|
||||
|
||||
include ../Makefile.vars
|
||||
|
||||
SRC_LIBRARY_x64 = ../lib/nacl-x64-release/libosmand.nexe
|
||||
SRC_LIBRARY_x86 = ../lib/nacl-x86-release/libosmand.nexe
|
||||
|
||||
|
||||
LIBRARY_x64 = nacl/osmand-x64.nexe
|
||||
LIBRARY_x86 = nacl/osmand-x86.nexe
|
||||
|
||||
compile : all libraries
|
||||
|
||||
libraries : $(LIBRARY_x64) $(LIBRARY_x86)
|
||||
|
||||
all : x86 x64
|
||||
x86:
|
||||
make -f Makefile ARCH=x86 TARGET=nacl
|
||||
|
||||
x64:
|
||||
make -f Makefile ARCH=x64 TARGET=nacl
|
||||
|
||||
$(LIBRARY_x86) : $(SRC_LIBRARY_x86)
|
||||
cp $(SRC_LIBRARY_x86) $(LIBRARY_x86)
|
||||
|
||||
$(LIBRARY_x64) : $(SRC_LIBRARY_x64)
|
||||
cp $(SRC_LIBRARY_x64) $(LIBRARY_x64)
|
||||
|
||||
#NMF_FILE = $(LIBNAME).nmf
|
||||
## NMF Manifiest generation
|
||||
##
|
||||
## Use the python script create_nmf to scan the binaries for dependencies using
|
||||
## objdump. Pass in the (-L) paths to the default library toolchains so that we
|
||||
## can find those libraries and have it automatically copy the files (-s) to
|
||||
## the target directory for us.
|
||||
#NMF:=python $(NACL_SDK_ROOT)/tools/create_nmf.py
|
||||
#NMF_ARGS:=-D $(TC_PATH)/x86_64-nacl/bin/objdump
|
||||
#NMF_PATHS:=-L $(TC_PATH)/x86_64-nacl/lib32 -L $(TC_PATH)/x86_64-nacl/lib
|
||||
#
|
||||
#$(NMF_FILE) : $(LIBRARY_x64) $(LIBRARY_x86)
|
||||
# $(NMF) $(NMF_ARGS) -s . -o $@ $(NMF_PATHS) $^
|
||||
|
||||
# Define a phony rule so it always runs, to build nexe and start up server.
|
||||
.PHONY: run
|
||||
run : all libraries
|
||||
python httpd.py 5100 &
|
||||
|
||||
stop :
|
||||
wget -q -O - 'http://localhost:5100?quit=1' > /dev/null
|
|
@ -1,127 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""A tiny web server.
|
||||
|
||||
This is intended to be used for testing, and only run from within the examples
|
||||
directory.
|
||||
"""
|
||||
|
||||
import BaseHTTPServer
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import SimpleHTTPServer
|
||||
import SocketServer
|
||||
import sys
|
||||
import urlparse
|
||||
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
|
||||
# Using 'localhost' means that we only accept connections
|
||||
# via the loop back interface.
|
||||
SERVER_PORT = 5103
|
||||
SERVER_HOST = ''
|
||||
|
||||
# We only run from the examples directory so that not too much is exposed
|
||||
# via this HTTP server. Everything in the directory is served, so there should
|
||||
# never be anything potentially sensitive in the serving directory, especially
|
||||
# if the machine might be a multi-user machine and not all users are trusted.
|
||||
# We only serve via the loopback interface.
|
||||
def SanityCheckDirectory():
|
||||
httpd_path = os.path.abspath(os.path.dirname(__file__))
|
||||
serve_path = os.path.abspath(os.getcwd())
|
||||
|
||||
# Verify we are serving from the directory this script came from, or bellow
|
||||
if serve_path[:len(httpd_path)] == httpd_path:
|
||||
return
|
||||
logging.error('For security, httpd.py should only be run from within the')
|
||||
logging.error('example directory tree.')
|
||||
logging.error('We are currently in %s.' % serve_path)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# An HTTP server that will quit when |is_running| is set to False. We also use
|
||||
# SocketServer.ThreadingMixIn in order to handle requests asynchronously for
|
||||
# faster responses.
|
||||
class QuittableHTTPServer(SocketServer.ThreadingMixIn,
|
||||
BaseHTTPServer.HTTPServer):
|
||||
def serve_forever(self, timeout=0.5):
|
||||
self.is_running = True
|
||||
self.timeout = timeout
|
||||
while self.is_running:
|
||||
self.handle_request()
|
||||
|
||||
def shutdown(self):
|
||||
self.is_running = False
|
||||
return 1
|
||||
|
||||
|
||||
# "Safely" split a string at |sep| into a [key, value] pair. If |sep| does not
|
||||
# exist in |str|, then the entire |str| is the key and the value is set to an
|
||||
# empty string.
|
||||
def KeyValuePair(str, sep='='):
|
||||
if sep in str:
|
||||
return str.split(sep)
|
||||
else:
|
||||
return [str, '']
|
||||
|
||||
|
||||
# A small handler that looks for '?quit=1' query in the path and shuts itself
|
||||
# down if it finds that parameter.
|
||||
class QuittableHTTPHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
(_, _, _, query, _) = urlparse.urlsplit(self.path)
|
||||
url_params = dict([KeyValuePair(key_value)
|
||||
for key_value in query.split('&')])
|
||||
if 'quit' in url_params and '1' in url_params['quit']:
|
||||
self.send_response(200, 'OK')
|
||||
self.send_header('Content-type', 'text/html')
|
||||
self.send_header('Content-length', '0')
|
||||
self.end_headers()
|
||||
self.server.shutdown()
|
||||
return
|
||||
|
||||
SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
|
||||
|
||||
|
||||
def Run(server_address,
|
||||
server_class=QuittableHTTPServer,
|
||||
handler_class=QuittableHTTPHandler):
|
||||
httpd = server_class(server_address, handler_class)
|
||||
logging.info("Starting local server on port %d", server_address[1])
|
||||
logging.info("To shut down send http://localhost:%d?quit=1",
|
||||
server_address[1])
|
||||
try:
|
||||
httpd.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Received keyboard interrupt.")
|
||||
httpd.server_close()
|
||||
|
||||
logging.info("Shutting down local server on port %d", server_address[1])
|
||||
|
||||
|
||||
def main():
|
||||
usage_str = "usage: %prog [options] [optional_portnum]"
|
||||
parser = optparse.OptionParser(usage=usage_str)
|
||||
parser.add_option(
|
||||
'--no_dir_check', dest='do_safe_check',
|
||||
action='store_false', default=True,
|
||||
help='Do not ensure that httpd.py is being run from a safe directory.')
|
||||
(options, args) = parser.parse_args(sys.argv)
|
||||
if options.do_safe_check:
|
||||
SanityCheckDirectory()
|
||||
if len(args) > 2:
|
||||
print 'Too many arguments specified.'
|
||||
parser.print_help()
|
||||
elif len(args) == 2:
|
||||
Run((SERVER_HOST, int(args[1])))
|
||||
else:
|
||||
Run((SERVER_HOST, SERVER_PORT))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
2
Osmand-kernel/osmand/nacl/.gitignore
vendored
2
Osmand-kernel/osmand/nacl/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
osmand-*.nexe
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview This file provides a BrowserChecker Javascript class.
|
||||
* Users can create a BrowserChecker object, invoke checkBrowser(|version|),
|
||||
* and then use getIsValidBrowser() and getBrowserSupportStatus()
|
||||
* to determine if the browser version is greater than |version|
|
||||
* and if the Native Client plugin is found.
|
||||
*/
|
||||
|
||||
// Create a namespace object
|
||||
var browser_version = browser_version || {};
|
||||
|
||||
/**
|
||||
* Class to provide checking for version and NativeClient.
|
||||
* @param {integer} arg1 An argument that indicates major version of Chrome we
|
||||
* require, such as 14.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructor for the BrowserChecker. Sets the major version of
|
||||
* Chrome that is required to |minChromeVersion|.
|
||||
* @param minChromeVersion The earliest major version of chrome that
|
||||
* is supported. If the Chrome browser version is less than
|
||||
* |minChromeVersion| then |isValidBrowswer| will be set to false.
|
||||
* @param opt_maxChromeVersion Ignored. Retained for backwards compatibility.
|
||||
* @param appVersion The application version string.
|
||||
* @param plugins The plugins that exist in the browser.
|
||||
* @constructor
|
||||
*/
|
||||
browser_version.BrowserChecker = function(minChromeVersion,
|
||||
appVersion, plugins,
|
||||
opt_maxChromeVersion) {
|
||||
/**
|
||||
* Version specified by the user. This class looks to see if the browser
|
||||
* version is >= |minChromeVersion_|.
|
||||
* @type {integer}
|
||||
* @private
|
||||
*/
|
||||
this.minChromeVersion_ = minChromeVersion;
|
||||
|
||||
/**
|
||||
* List of Browser plugin objects.
|
||||
* @type {Ojbect array}
|
||||
* @private
|
||||
*/
|
||||
this.plugins_ = plugins;
|
||||
|
||||
/**
|
||||
* Application version string from the Browser.
|
||||
* @type {integer}
|
||||
* @private
|
||||
*/
|
||||
this.appVersion_ = appVersion;
|
||||
|
||||
/**
|
||||
* Flag used to indicate if the browser has Native Client and is if the
|
||||
* browser version is recent enough.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.isValidBrowser_ = false;
|
||||
|
||||
/**
|
||||
* Actual major version of Chrome -- found by querying the browser.
|
||||
* @type {integer}
|
||||
* @private
|
||||
*/
|
||||
this.chromeVersion_ = null;
|
||||
|
||||
/**
|
||||
* Browser support status. This allows the user to get a detailed status
|
||||
* rather than using this.browserSupportMessage.
|
||||
*/
|
||||
this.browserSupportStatus_ =
|
||||
browser_version.BrowserChecker.StatusValues.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* The values used for BrowserChecker status to indicate success or
|
||||
* a specific error.
|
||||
* @enum {id}
|
||||
*/
|
||||
browser_version.BrowserChecker.StatusValues = {
|
||||
UNKNOWN: 0,
|
||||
NACL_ENABLED: 1,
|
||||
UNKNOWN_BROWSER: 2,
|
||||
CHROME_VERSION_TOO_OLD: 3,
|
||||
NACL_NOT_ENABLED: 4,
|
||||
NOT_USING_SERVER: 5
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the plugin with name |name| exists in the browser.
|
||||
* @param {string} name The name of the plugin.
|
||||
* @param {Object array} plugins The plugins in this browser.
|
||||
* @return {bool} |true| if the plugin is found.
|
||||
*/
|
||||
browser_version.BrowserChecker.prototype.pluginExists = function(name,
|
||||
plugins) {
|
||||
for (var index=0; index < plugins.length; index++) {
|
||||
var plugin = this.plugins_[index];
|
||||
var plugin_name = plugin['name'];
|
||||
// If the plugin is not found, you can use the Javascript console
|
||||
// to see the names of the plugins that were found when debugging.
|
||||
if (plugin_name.indexOf(name) != -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns browserSupportStatus_ which indicates if the browser supports
|
||||
* Native Client. Values are defined as literals in
|
||||
* browser_version.BrowserChecker.StatusValues.
|
||||
* @ return {int} Level of NaCl support.
|
||||
*/
|
||||
browser_version.BrowserChecker.prototype.getBrowserSupportStatus = function() {
|
||||
return this.browserSupportStatus_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns isValidBrowser (true/false) to indicate if the browser supports
|
||||
* Native Client.
|
||||
* @ return {bool} If this browser has NativeClient and correct version.
|
||||
*/
|
||||
browser_version.BrowserChecker.prototype.getIsValidBrowser = function() {
|
||||
return this.isValidBrowser_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if this browser can support Native Client applications.
|
||||
* For Chrome browsers, checks to see if the "Native Client" plugin is
|
||||
* enabled.
|
||||
*/
|
||||
browser_version.BrowserChecker.prototype.checkBrowser = function() {
|
||||
var versionPatt = /Chrome\/(\d+)\.(\d+)\.(\d+)\.(\d+)/;
|
||||
var result = this.appVersion_.match(versionPatt);
|
||||
|
||||
// |result| stores the Chrome version number.
|
||||
if (!result) {
|
||||
this.isValidBrowser_ = false;
|
||||
this.browserSupportStatus_ =
|
||||
browser_version.BrowserChecker.StatusValues.UNKNOWN_BROWSER;
|
||||
} else {
|
||||
this.chromeVersion_ = result[1];
|
||||
// We know we have Chrome, check version and/or plugin named Native Client
|
||||
if (this.chromeVersion_ >= this.minChromeVersion_) {
|
||||
var found_nacl = this.pluginExists('Native Client', this.plugins_);
|
||||
if (found_nacl) {
|
||||
this.isValidBrowser_ = true;
|
||||
this.browserSupportStatus_ =
|
||||
browser_version.BrowserChecker.StatusValues.NACL_ENABLED;
|
||||
} else {
|
||||
this.isValidBrowser_ = false;
|
||||
this.browserSupportStatus_ =
|
||||
browser_version.BrowserChecker.StatusValues.NACL_NOT_ENABLED;
|
||||
}
|
||||
} else {
|
||||
// We are in a version that is less than |minChromeVersion_|
|
||||
this.isValidBrowser_ = false;
|
||||
this.browserSupportStatus_ =
|
||||
browser_version.BrowserChecker.StatusValues.CHROME_VERSION_TOO_OLD;
|
||||
}
|
||||
}
|
||||
var my_protocol = window.location.protocol;
|
||||
if (my_protocol.indexOf('file') == 0) {
|
||||
this.isValidBrowser_ = false;
|
||||
this.browserSupportStatus_ =
|
||||
browser_version.BrowserChecker.StatusValues.NOT_USING_SERVER;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,241 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file.
|
||||
-->
|
||||
<head>
|
||||
<title>Load Progress Example</title>
|
||||
<script type="text/javascript" src="check_browser.js"></script>
|
||||
<script type="text/javascript">
|
||||
// Check for Native Client support in the browser before the DOM loads.
|
||||
var isValidBrowser = false;
|
||||
var browserSupportStatus = 0;
|
||||
var checker = new browser_version.BrowserChecker(
|
||||
14, // Minumum Chrome version.
|
||||
navigator["appVersion"],
|
||||
navigator["plugins"]);
|
||||
checker.checkBrowser();
|
||||
|
||||
loadProgressModule = null; // Global application object.
|
||||
statusText = 'NO-STATUS';
|
||||
|
||||
isValidBrowser = checker.getIsValidBrowser();
|
||||
browserSupportStatus = checker.getBrowserSupportStatus();
|
||||
|
||||
// Handler that gets called when the NaCl module starts loading. This
|
||||
// event is always triggered when an <EMBED> tag has a MIME type of
|
||||
// application/x-nacl.
|
||||
function moduleDidStartLoad() {
|
||||
appendToEventLog('loadstart');
|
||||
}
|
||||
|
||||
// Progress event handler. |event| contains a couple of interesting
|
||||
// properties that are used in this example:
|
||||
// total The size of the NaCl module in bytes. Note that this value
|
||||
// is 0 until |lengthComputable| is true. In particular, this
|
||||
// value is 0 for the first 'progress' event.
|
||||
// loaded The number of bytes loaded so far.
|
||||
// lengthComputable A boolean indicating that the |total| field
|
||||
// represents a valid length.
|
||||
//
|
||||
// event The ProgressEvent that triggered this handler.
|
||||
function moduleLoadProgress(event) {
|
||||
var loadPercent = 0.0;
|
||||
var loadPercentString;
|
||||
if (event.lengthComputable && event.total > 0) {
|
||||
loadPercent = event.loaded / event.total * 100.0;
|
||||
loadPercentString = loadPercent + '%';
|
||||
} else {
|
||||
// The total length is not yet known.
|
||||
loadPercent = -1.0;
|
||||
loadPercentString = 'Computing...';
|
||||
}
|
||||
appendToEventLog('progress: ' + loadPercentString +
|
||||
' (' + event.loaded + ' of ' + event.total + ' bytes)');
|
||||
}
|
||||
|
||||
// Handler that gets called if an error occurred while loading the NaCl
|
||||
// module. Note that the event does not carry any meaningful data about
|
||||
// the error, you have to check lastError on the <EMBED> element to find
|
||||
// out what happened.
|
||||
function moduleLoadError() {
|
||||
appendToEventLog('error: ' + loadProgressModule.lastError);
|
||||
}
|
||||
|
||||
// Handler that gets called if the NaCl module load is aborted.
|
||||
function moduleLoadAbort() {
|
||||
appendToEventLog('abort');
|
||||
}
|
||||
|
||||
var piGenerator = null;
|
||||
var paintInterval = null;
|
||||
|
||||
// Start up the paint timer when the NaCl module has loaded.
|
||||
function moduleDidLoad() {
|
||||
loadProgressModule = document.getElementById('load_progress');
|
||||
appendToEventLog('load');
|
||||
updateStatus('SUCCESS');
|
||||
piGenerator = document.getElementById('load_progress');
|
||||
paintInterval = setInterval('load_progress.postMessage("paint")', 50);
|
||||
}
|
||||
function pageDidUnload() {
|
||||
clearInterval(paintInterval);
|
||||
}
|
||||
|
||||
// Handler that gets called when the NaCl module loading has completed.
|
||||
// You will always get one of these events, regardless of whether the NaCl
|
||||
// module loaded successfully or not. For example, if there is an error
|
||||
// during load, you will get an 'error' event and a 'loadend' event. Note
|
||||
// that if the NaCl module loads successfully, you will get both a 'load'
|
||||
// event and a 'loadend' event.
|
||||
function moduleDidEndLoad() {
|
||||
appendToEventLog('loadend');
|
||||
var lastError = event.target.lastError;
|
||||
if (lastError == undefined || lastError.length == 0) {
|
||||
lastError = '<none>';
|
||||
}
|
||||
appendToEventLog('lastError: ' + lastError);
|
||||
}
|
||||
|
||||
|
||||
// Handle a message coming from the NaCl module.
|
||||
function handleMessage(message_event) {
|
||||
// alert(message_event.data);
|
||||
//document.form.pi.value = message_event.data;
|
||||
}
|
||||
|
||||
// Set the global status message. Updates the 'status_field' element with
|
||||
// the new text.
|
||||
// opt_message The message text. If this is null or undefined, then
|
||||
// attempt to set the element with id 'status_field' to the value of
|
||||
// |statusText|.
|
||||
function updateStatus(opt_message) {
|
||||
if (opt_message)
|
||||
statusText = opt_message;
|
||||
var statusField = document.getElementById('status_field');
|
||||
if (statusField) {
|
||||
statusField.innerHTML = statusText;
|
||||
}
|
||||
}
|
||||
|
||||
// Append an event name to the 'event_log_field' element. Event names
|
||||
// are separated by a <br> tag so they get listed one per line.
|
||||
// logMessage The message to append to the log.
|
||||
function appendToEventLog(logMessage) {
|
||||
var eventLogField = document.getElementById('event_log_field');
|
||||
if (eventLogField.innerHTML.length == 0) {
|
||||
eventLogField.innerHTML = logMessage;
|
||||
} else {
|
||||
eventLogField.innerHTML = eventLogField.innerHTML +
|
||||
'<br />' +
|
||||
logMessage;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Native Client Load Event Example</h1>
|
||||
|
||||
<h2>Event Log</h2>
|
||||
<div id="event_log_field"></div>
|
||||
<h2>Status</h2>
|
||||
<div id="status_field">NO-STATUS</div>
|
||||
|
||||
<div id="listener">
|
||||
<script type="text/javascript">
|
||||
var listener = document.getElementById('listener');
|
||||
listener.addEventListener('loadstart', moduleDidStartLoad, true);
|
||||
listener.addEventListener('progress', moduleLoadProgress, true);
|
||||
listener.addEventListener('error', moduleLoadError, true);
|
||||
listener.addEventListener('abort', moduleLoadAbort, true);
|
||||
listener.addEventListener('load', moduleDidLoad, true);
|
||||
listener.addEventListener('loadend', moduleDidEndLoad, true);
|
||||
listener.addEventListener('message', handleMessage, true);
|
||||
|
||||
switch (browserSupportStatus) {
|
||||
case browser_version.BrowserChecker.StatusValues.NACL_ENABLED:
|
||||
appendToEventLog('Native Client plugin enabled.');
|
||||
break;
|
||||
case browser_version.BrowserChecker.StatusValues.UNKNOWN_BROWSER:
|
||||
updateStatus('UNKNOWN BROWSER');
|
||||
break;
|
||||
case browser_version.BrowserChecker.StatusValues.CHROME_VERSION_TOO_OLD:
|
||||
appendToEventLog(
|
||||
'Chrome too old: You must use Chrome version 14 or later.');
|
||||
updateStatus('NEED CHROME 14 OR LATER');
|
||||
break;
|
||||
case browser_version.BrowserChecker.StatusValues.NACL_NOT_ENABLED:
|
||||
appendToEventLog(
|
||||
'NaCl disabled: Native Client is not enabled.<br>' +
|
||||
'Please go to <b>chrome://plugins</b> and enable Native Client ' +
|
||||
'plugin.');
|
||||
updateStatus('NaCl NOT ENABLED');
|
||||
break;
|
||||
case browser_version.BrowserChecker.StatusValues.NOT_USING_SERVER:
|
||||
appendToEventLog(
|
||||
'file: URL detected, please use a web server to host Native ' +
|
||||
'Client applications.');
|
||||
updateStatus('NaCl NOT ENABLED');
|
||||
default:
|
||||
appendToEventLog('Unknown error: Unable to detect browser and/or ' +
|
||||
'Native Client support.');
|
||||
updateStatus('UNKNOWN ERROR');
|
||||
break;
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Load the published .nexe. This includes the 'src' attribute which
|
||||
shows how to load multi-architecture modules. Each entry in the "nexes"
|
||||
object in the .nmf manifest file is a key-value pair: the key is the runtime
|
||||
('x86-32', 'x86-64', etc.); the value is a URL for the desired NaCl module.
|
||||
To load the debug versions of your .nexes, set the 'src' attribute to the
|
||||
_dbg.nmf version of the manifest file.
|
||||
|
||||
Note: The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
|
||||
and a 'message' event listener attached. This wrapping method is used
|
||||
instead of attaching the event listeners directly to the <EMBED> element to
|
||||
ensure that the listeners are active before the NaCl module 'load' event
|
||||
fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or
|
||||
pp::Instance.PostMessage() (in C++) from within the initialization code in
|
||||
your NaCl module.
|
||||
-->
|
||||
<embed name="nacl_module"
|
||||
id="load_progress"
|
||||
width=500 height=500
|
||||
src="osmand.nmf"
|
||||
type="application/x-nacl" />
|
||||
|
||||
<script type="text/javascript">
|
||||
loadProgressModule = document.getElementById('load_progress');
|
||||
// Futher diagnose NaCl loading.
|
||||
if (loadProgressModule == null ||
|
||||
typeof loadProgressModule.readyState == 'undefined') {
|
||||
switch (browserSupportStatus) {
|
||||
case browser_version.BrowserChecker.StatusValues.NACL_ENABLED:
|
||||
// The NaCl plugin is enabled and running, it's likely that the flag
|
||||
// isn't set.
|
||||
appendToEventLog(
|
||||
'NaCl flag disabled: The Native Client flag is not enabled.<br>' +
|
||||
'Please go to <b>chrome://flags</b> enable Native Client and ' +
|
||||
'relaunch your browser. See also: ' +
|
||||
'<a href="http://code.google.com/chrome/nativeclient/docs/' +
|
||||
'running.html">Running Web Applications that Use Native Client' +
|
||||
'</a>');
|
||||
updateStatus('NaCl NOT ENABLED');
|
||||
break;
|
||||
case browser_version.BrowserChecker.StatusValues.UNKNOWN_BROWSER:
|
||||
appendToEventLog('Native Client applications are not supported by ' +
|
||||
'this browser.');
|
||||
break;
|
||||
default:
|
||||
appendToEventLog('Unknown error when loading Native Client ' +
|
||||
'application.');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,87 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file.
|
||||
-->
|
||||
<head>
|
||||
<title>Hello, World!</title>
|
||||
<script type="text/javascript">
|
||||
helloWorldModule = null; // Global application object.
|
||||
statusText = 'NO-STATUS';
|
||||
|
||||
// Indicate success when the NaCl module has loaded.
|
||||
function moduleDidLoad() {
|
||||
helloWorldModule = document.getElementById('hello_world');
|
||||
updateStatus('SUCCESS');
|
||||
}
|
||||
|
||||
// Handle a message coming from the NaCl module.
|
||||
function handleMessage(message_event) {
|
||||
alert(message_event.data);
|
||||
}
|
||||
|
||||
// If the page loads before the Native Client module loads, then set the
|
||||
// status message indicating that the module is still loading. Otherwise,
|
||||
// do not change the status message.
|
||||
function pageDidLoad() {
|
||||
if (helloWorldModule == null) {
|
||||
updateStatus('LOADING...');
|
||||
} else {
|
||||
// It's possible that the Native Client module onload event fired
|
||||
// before the page's onload event. In this case, the status message
|
||||
// will reflect 'SUCCESS', but won't be displayed. This call will
|
||||
// display the current message.
|
||||
updateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
// Set the global status message. If the element with id 'statusField'
|
||||
// exists, then set its HTML to the status message as well.
|
||||
// opt_message The message test. If this is null or undefined, then
|
||||
// attempt to set the element with id 'statusField' to the value of
|
||||
// |statusText|.
|
||||
function updateStatus(opt_message) {
|
||||
if (opt_message)
|
||||
statusText = opt_message;
|
||||
var statusField = document.getElementById('statusField');
|
||||
if (statusField) {
|
||||
statusField.innerHTML = statusText;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="pageDidLoad()">
|
||||
|
||||
<h1>Native Client Simple Module</h1>
|
||||
<h2>Status: <code id="statusField">NO-STATUS</code></h2>
|
||||
<!-- The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
|
||||
and a 'message' event listener attached. This wrapping method is used
|
||||
instead of attaching the event listeners directly to the <EMBED> element to
|
||||
ensure that the listeners are active before the NaCl module 'load' event
|
||||
fires. This also allows you to use PPB_Messaging.PostMessage() (in C) or
|
||||
pp::Instance.PostMessage() (in C++) from within the initialization code in
|
||||
your NaCl module.
|
||||
|
||||
The src points to a manifest file, which provides the Native Client plug-in
|
||||
a mapping between architecture and NaCl Executable (NEXE).
|
||||
|
||||
We use a non-zero sized embed to give Chrome space to place the bad plug-in
|
||||
graphic, if there is a problem.
|
||||
-->
|
||||
<div id="listener">
|
||||
<script type="text/javascript">
|
||||
var listener = document.getElementById('listener')
|
||||
listener.addEventListener('load', moduleDidLoad, true);
|
||||
listener.addEventListener('message', handleMessage, true);
|
||||
</script>
|
||||
|
||||
<embed name="nacl_module"
|
||||
id="hello_world"
|
||||
width=200 height=200
|
||||
src="osmand.nmf"
|
||||
type="application/x-nacl" />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
|
||||
"program": {
|
||||
"x86-64": {
|
||||
"url": "osmand-x64.nexe"
|
||||
},
|
||||
"x86-32": {
|
||||
"url": "osmand-x86.nexe"
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,321 +0,0 @@
|
|||
#ifndef _OSMAND_BINARY_READ_H
|
||||
#define _OSMAND_BINARY_READ_H
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include "mapObjects.h"
|
||||
#include "multipolygons.h"
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#include "mapObjects.h"
|
||||
#include "renderRules.h"
|
||||
|
||||
static const int MAP_VERSION = 2;
|
||||
static const int BASEMAP_ZOOM = 11;
|
||||
|
||||
|
||||
struct MapTreeBounds {
|
||||
uint32_t length;
|
||||
uint32_t filePointer;
|
||||
uint32_t mapDataBlock;
|
||||
uint32_t left ;
|
||||
uint32_t right ;
|
||||
uint32_t top ;
|
||||
uint32_t bottom;
|
||||
bool ocean;
|
||||
|
||||
MapTreeBounds() {
|
||||
ocean = -1;
|
||||
}
|
||||
};
|
||||
struct RoutingIndex;
|
||||
struct RouteSubregion {
|
||||
uint32_t length;
|
||||
uint32_t filePointer;
|
||||
uint32_t mapDataBlock;
|
||||
uint32_t left;
|
||||
uint32_t right;
|
||||
uint32_t top;
|
||||
uint32_t bottom;
|
||||
std::vector<RouteSubregion> subregions;
|
||||
RoutingIndex* routingIndex;
|
||||
|
||||
RouteSubregion(RoutingIndex* ind) : length(0), filePointer(0), mapDataBlock(0), routingIndex(ind){
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct MapRoot: MapTreeBounds {
|
||||
int minZoom ;
|
||||
int maxZoom ;
|
||||
std::vector<MapTreeBounds> bounds;
|
||||
};
|
||||
|
||||
enum PART_INDEXES {
|
||||
MAP_INDEX = 1,
|
||||
POI_INDEX,
|
||||
ADDRESS_INDEX,
|
||||
TRANSPORT_INDEX,
|
||||
ROUTING_INDEX,
|
||||
};
|
||||
|
||||
struct BinaryPartIndex {
|
||||
uint32_t length;
|
||||
int filePointer;
|
||||
PART_INDEXES type;
|
||||
std::string name;
|
||||
|
||||
BinaryPartIndex(PART_INDEXES tp) : type(tp) {}
|
||||
};
|
||||
|
||||
struct RoutingIndex : BinaryPartIndex {
|
||||
// UNORDERED(map)< uint32_t, tag_value > decodingRules;
|
||||
vector< tag_value > decodingRules;
|
||||
std::vector<RouteSubregion> subregions;
|
||||
std::vector<RouteSubregion> basesubregions;
|
||||
RoutingIndex() : BinaryPartIndex(ROUTING_INDEX) {
|
||||
}
|
||||
|
||||
void initRouteEncodingRule(uint32_t id, std::string tag, std::string val) {
|
||||
tag_value pair = tag_value(tag, val);
|
||||
// DEFINE hash
|
||||
//encodingRules[pair] = id;
|
||||
while(decodingRules.size() < id + 1){
|
||||
decodingRules.push_back(pair);
|
||||
}
|
||||
decodingRules[id] = pair;
|
||||
}
|
||||
};
|
||||
|
||||
struct RouteDataObject {
|
||||
RoutingIndex* region;
|
||||
std::vector<uint32_t> types ;
|
||||
std::vector<uint32_t> pointsX ;
|
||||
std::vector<uint32_t> pointsY ;
|
||||
std::vector<uint64_t> restrictions ;
|
||||
std::vector<std::vector<uint32_t> > pointTypes;
|
||||
int64_t id;
|
||||
|
||||
UNORDERED(map)<int, std::string > names;
|
||||
vector<pair<uint32_t, uint32_t> > namesIds;
|
||||
|
||||
string getName() {
|
||||
if(names.size() > 0) {
|
||||
return names.begin()->second;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
int getSize() {
|
||||
int s = sizeof(this);
|
||||
s += pointsX.capacity()*sizeof(uint32_t);
|
||||
s += pointsY.capacity()*sizeof(uint32_t);
|
||||
s += types.capacity()*sizeof(uint32_t);
|
||||
s += restrictions.capacity()*sizeof(uint64_t);
|
||||
std::vector<std::vector<uint32_t> >::iterator t = pointTypes.begin();
|
||||
for(;t!=pointTypes.end(); t++) {
|
||||
s+= (*t).capacity() * sizeof(uint32_t);
|
||||
}
|
||||
s += namesIds.capacity()*sizeof(pair<uint32_t, uint32_t>);
|
||||
s += names.size()*sizeof(pair<int, string>)*10;
|
||||
return s;
|
||||
}
|
||||
|
||||
double directionRoute(int startPoint, bool plus){
|
||||
// look at comment JAVA
|
||||
return directionRoute(startPoint, plus, 5);
|
||||
}
|
||||
|
||||
// Gives route direction of EAST degrees from NORTH ]-PI, PI]
|
||||
double directionRoute(int startPoint, bool plus, float dist) {
|
||||
int x = pointsX[startPoint];
|
||||
int y = pointsY[startPoint];
|
||||
int nx = startPoint;
|
||||
int px = x;
|
||||
int py = y;
|
||||
double total = 0;
|
||||
do {
|
||||
if (plus) {
|
||||
nx++;
|
||||
if (nx >= pointsX.size()) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
nx--;
|
||||
if (nx < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
px = pointsX[nx];
|
||||
py = pointsY[nx];
|
||||
// translate into meters
|
||||
total += abs(px - x) * 0.011 + abs(py - y) * 0.01863;
|
||||
} while (total < dist);
|
||||
return -atan2( (float)x - px, (float) y - py );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct MapIndex : BinaryPartIndex {
|
||||
|
||||
std::vector<MapRoot> levels;
|
||||
|
||||
UNORDERED(map)<int, tag_value > decodingRules;
|
||||
// DEFINE hash
|
||||
//UNORDERED(map)<tag_value, int> encodingRules;
|
||||
|
||||
int nameEncodingType;
|
||||
int refEncodingType;
|
||||
int coastlineEncodingType;
|
||||
int coastlineBrokenEncodingType;
|
||||
int landEncodingType;
|
||||
int onewayAttribute ;
|
||||
int onewayReverseAttribute ;
|
||||
UNORDERED(set)< int > positiveLayers;
|
||||
UNORDERED(set)< int > negativeLayers;
|
||||
|
||||
MapIndex() : BinaryPartIndex(MAP_INDEX) {
|
||||
nameEncodingType = refEncodingType = coastlineBrokenEncodingType = coastlineEncodingType = -1;
|
||||
landEncodingType = onewayAttribute = onewayReverseAttribute = -1;
|
||||
}
|
||||
|
||||
void finishInitializingTags() {
|
||||
int free = decodingRules.size() * 2 + 1;
|
||||
coastlineBrokenEncodingType = free++;
|
||||
initMapEncodingRule(0, coastlineBrokenEncodingType, "natural", "coastline_broken");
|
||||
if (landEncodingType == -1) {
|
||||
landEncodingType = free++;
|
||||
initMapEncodingRule(0, landEncodingType, "natural", "land");
|
||||
}
|
||||
}
|
||||
|
||||
void initMapEncodingRule(uint32_t type, uint32_t id, std::string tag, std::string val) {
|
||||
tag_value pair = tag_value(tag, val);
|
||||
// DEFINE hash
|
||||
//encodingRules[pair] = id;
|
||||
decodingRules[id] = pair;
|
||||
|
||||
if ("name" == tag) {
|
||||
nameEncodingType = id;
|
||||
} else if ("natural" == tag && "coastline" == val) {
|
||||
coastlineEncodingType = id;
|
||||
} else if ("natural" == tag && "land" == val) {
|
||||
landEncodingType = id;
|
||||
} else if ("oneway" == tag && "yes" == val) {
|
||||
onewayAttribute = id;
|
||||
} else if ("oneway" == tag && "-1" == val) {
|
||||
onewayReverseAttribute = id;
|
||||
} else if ("ref" == tag) {
|
||||
refEncodingType = id;
|
||||
} else if ("layer" == tag) {
|
||||
if (val != "" && val != "0") {
|
||||
if (val[0] == '-') {
|
||||
negativeLayers.insert(id);
|
||||
} else {
|
||||
positiveLayers.insert(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct BinaryMapFile {
|
||||
std::string inputName;
|
||||
uint32_t version;
|
||||
uint64_t dateCreated;
|
||||
std::vector<MapIndex> mapIndexes;
|
||||
std::vector<RoutingIndex*> routingIndexes;
|
||||
std::vector<BinaryPartIndex*> indexes;
|
||||
int fd;
|
||||
int routefd;
|
||||
bool basemap;
|
||||
|
||||
bool isBasemap(){
|
||||
return basemap;
|
||||
}
|
||||
|
||||
~BinaryMapFile() {
|
||||
close(fd);
|
||||
close(routefd);
|
||||
}
|
||||
};
|
||||
|
||||
struct ResultPublisher {
|
||||
std::vector< MapDataObject*> result;
|
||||
|
||||
bool publish(MapDataObject* r) {
|
||||
result.push_back(r);
|
||||
return true;
|
||||
}
|
||||
bool publish(std::vector<MapDataObject*> r) {
|
||||
result.insert(result.begin(), r.begin(), r.end());
|
||||
return true;
|
||||
}
|
||||
bool isCancelled() {
|
||||
return false;
|
||||
}
|
||||
virtual ~ResultPublisher() {
|
||||
deleteObjects(result);
|
||||
}
|
||||
};
|
||||
|
||||
struct SearchQuery {
|
||||
RenderingRuleSearchRequest* req;
|
||||
int left;
|
||||
int right;
|
||||
int top;
|
||||
int bottom;
|
||||
int zoom;
|
||||
ResultPublisher* publisher;
|
||||
|
||||
coordinates cacheCoordinates;
|
||||
bool ocean;
|
||||
bool mixed;
|
||||
|
||||
int numberOfVisitedObjects;
|
||||
int numberOfAcceptedObjects;
|
||||
int numberOfReadSubtrees;
|
||||
int numberOfAcceptedSubtrees;
|
||||
|
||||
SearchQuery(int l, int r, int t, int b, RenderingRuleSearchRequest* req, ResultPublisher* publisher) :
|
||||
req(req), left(l), right(r), top(t), bottom(b),publisher(publisher) {
|
||||
numberOfAcceptedObjects = numberOfVisitedObjects = 0;
|
||||
numberOfAcceptedSubtrees = numberOfReadSubtrees = 0;
|
||||
ocean = mixed = false;
|
||||
}
|
||||
SearchQuery(int l, int r, int t, int b) :
|
||||
left(l), right(r), top(t), bottom(b) {
|
||||
}
|
||||
|
||||
SearchQuery(){
|
||||
|
||||
}
|
||||
|
||||
bool publish(MapDataObject* obj) {
|
||||
return publisher->publish(obj);
|
||||
}
|
||||
};
|
||||
|
||||
void searchRouteSubregions(SearchQuery* q, std::vector<RouteSubregion>& tempResult);
|
||||
|
||||
void searchRouteDataForSubRegion(SearchQuery* q, std::vector<RouteDataObject*>& list, RouteSubregion* sub);
|
||||
|
||||
ResultPublisher* searchObjectsForRendering(SearchQuery* q, bool skipDuplicates, int renderRouteDataFile, std::string msgNothingFound);
|
||||
|
||||
BinaryMapFile* initBinaryMapFile(std::string inputName);
|
||||
|
||||
bool initMapFilesFromCache(std::string inputName) ;
|
||||
|
||||
bool closeBinaryMapFile(std::string inputName);
|
||||
|
||||
#endif
|
|
@ -1,681 +0,0 @@
|
|||
#include "common.h"
|
||||
#include <queue>
|
||||
#include "binaryRead.h"
|
||||
#include "binaryRoutePlanner.h"
|
||||
#include <functional>
|
||||
|
||||
static bool PRINT_TO_CONSOLE_ROUTE_INFORMATION_TO_TEST = true;
|
||||
static const int REVERSE_WAY_RESTRICTION_ONLY = 1024;
|
||||
|
||||
static const int ROUTE_POINTS = 11;
|
||||
static const float TURN_DEGREE_MIN = 45;
|
||||
static const short RESTRICTION_NO_RIGHT_TURN = 1;
|
||||
static const short RESTRICTION_NO_LEFT_TURN = 2;
|
||||
static const short RESTRICTION_NO_U_TURN = 3;
|
||||
static const short RESTRICTION_NO_STRAIGHT_ON = 4;
|
||||
static const short RESTRICTION_ONLY_RIGHT_TURN = 5;
|
||||
static const short RESTRICTION_ONLY_LEFT_TURN = 6;
|
||||
static const short RESTRICTION_ONLY_STRAIGHT_ON = 7;
|
||||
static const bool TRACE_ROUTING = false;
|
||||
|
||||
inline int roadPriorityComparator(float o1DistanceFromStart, float o1DistanceToEnd, float o2DistanceFromStart,
|
||||
float o2DistanceToEnd, float heuristicCoefficient) {
|
||||
// f(x) = g(x) + h(x) --- g(x) - distanceFromStart, h(x) - distanceToEnd (not exact)
|
||||
float f1 = o1DistanceFromStart + heuristicCoefficient * o1DistanceToEnd;
|
||||
float f2 = o2DistanceFromStart + heuristicCoefficient * o2DistanceToEnd;
|
||||
if (f1 == f2) {
|
||||
return 0;
|
||||
}
|
||||
return f1 < f2 ? -1 : 1;
|
||||
}
|
||||
|
||||
// translate into meters
|
||||
static double squareRootDist(int x1, int y1, int x2, int y2) {
|
||||
double dy = convert31YToMeters(y1, y2);
|
||||
double dx = convert31XToMeters(x1, x2);
|
||||
return sqrt(dx * dx + dy * dy);
|
||||
// return measuredDist(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
static double squareDist(int x1, int y1, int x2, int y2) {
|
||||
// translate into meters
|
||||
double dy = convert31YToMeters(y1, y2);
|
||||
double dx = convert31XToMeters(x1, x2);
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
static double h(RoutingContext* ctx, float distanceToFinalPoint, SHARED_PTR<RouteSegment> next) {
|
||||
return distanceToFinalPoint / ctx->config.getMaxDefaultSpeed();
|
||||
|
||||
}
|
||||
static double h(RoutingContext* ctx, int targetEndX, int targetEndY, int startX, int startY) {
|
||||
double distance = squareRootDist(startX, startY, targetEndX, targetEndY);
|
||||
return distance / ctx->config.getMaxDefaultSpeed();
|
||||
}
|
||||
|
||||
struct SegmentsComparator: public std::binary_function<SHARED_PTR<RouteSegment>, SHARED_PTR<RouteSegment>, bool>
|
||||
{
|
||||
RoutingContext* ctx;
|
||||
SegmentsComparator(RoutingContext* c) : ctx(c) {
|
||||
|
||||
}
|
||||
bool operator()(const SHARED_PTR<RouteSegment> lhs, const SHARED_PTR<RouteSegment> rhs) const
|
||||
{
|
||||
int cmp = roadPriorityComparator(lhs.get()->distanceFromStart, lhs.get()->distanceToEnd, rhs.get()->distanceFromStart,
|
||||
rhs.get()->distanceToEnd, ctx->getHeuristicCoefficient());
|
||||
return cmp > 0;
|
||||
}
|
||||
};
|
||||
struct NonHeuristicSegmentsComparator: public std::binary_function<SHARED_PTR<RouteSegment>, SHARED_PTR<RouteSegment>, bool>
|
||||
{
|
||||
bool operator()(const SHARED_PTR<RouteSegment> lhs, const SHARED_PTR<RouteSegment> rhs) const
|
||||
{
|
||||
return roadPriorityComparator(lhs.get()->distanceFromStart, lhs.get()->distanceToEnd, rhs.get()->distanceFromStart, rhs.get()->distanceToEnd, 0.5) > 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef UNORDERED(map)<int64_t, SHARED_PTR<RouteSegment> > VISITED_MAP;
|
||||
typedef priority_queue<SHARED_PTR<RouteSegment>, vector<SHARED_PTR<RouteSegment> >, SegmentsComparator > SEGMENTS_QUEUE;
|
||||
bool processRouteSegment(RoutingContext* ctx, bool reverseWaySearch, SEGMENTS_QUEUE& graphSegments,
|
||||
VISITED_MAP& visitedSegments, int targetEndX, int targetEndY, SHARED_PTR<RouteSegment> segment, VISITED_MAP&oppositeSegments);
|
||||
bool processIntersections(RoutingContext* ctx, SEGMENTS_QUEUE& graphSegments, VISITED_MAP& visitedSegments,
|
||||
VISITED_MAP& oppositeSegments, double distFromStart, double distToFinalPoint, SHARED_PTR<RouteSegment> segment,int segmentEnd, SHARED_PTR<RouteSegment> inputNext,
|
||||
bool reverseWay);
|
||||
|
||||
int calculateSizeOfSearchMaps(SEGMENTS_QUEUE graphDirectSegments, SEGMENTS_QUEUE graphReverseSegments,
|
||||
VISITED_MAP visitedDirectSegments, VISITED_MAP visitedOppositeSegments) {
|
||||
int sz = visitedDirectSegments.size() * sizeof(pair<int64_t, SHARED_PTR<RouteSegment> > );
|
||||
sz += visitedOppositeSegments.size()*sizeof(pair<int64_t, SHARED_PTR<RouteSegment> >);
|
||||
sz += graphDirectSegments.size()*sizeof(SHARED_PTR<RouteSegment>);
|
||||
sz += graphReverseSegments.size()*sizeof(SHARED_PTR<RouteSegment>);
|
||||
return sz;
|
||||
}
|
||||
/**
|
||||
* Calculate route between start.segmentEnd and end.segmentStart (using A* algorithm)
|
||||
* return list of segments
|
||||
*/
|
||||
void searchRouteInternal(RoutingContext* ctx, SHARED_PTR<RouteSegment> start, SHARED_PTR<RouteSegment> end, bool leftSideNavigation) {
|
||||
// FIXME intermediate points
|
||||
// measure time
|
||||
ctx->visitedSegments = 0;
|
||||
int iterationsToUpdate = 0;
|
||||
ctx->timeToCalculate.start();
|
||||
if(ctx->config.initialDirection > -180 && ctx->config.initialDirection < 180) {
|
||||
ctx->firstRoadId = (start->road->id << ROUTE_POINTS) + start->getSegmentStart();
|
||||
double plusDir = start->road->directionRoute(start->getSegmentStart(), true);
|
||||
double diff = plusDir - ctx->config.initialDirection;
|
||||
if(abs(alignAngleDifference(diff)) <= M_PI / 3) {
|
||||
ctx->firstRoadDirection = 1;
|
||||
} else if(abs(alignAngleDifference(diff - M_PI )) <= M_PI / 3) {
|
||||
ctx->firstRoadDirection = -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SegmentsComparator sgmCmp(ctx);
|
||||
SEGMENTS_QUEUE graphDirectSegments(sgmCmp);
|
||||
SEGMENTS_QUEUE graphReverseSegments(sgmCmp);
|
||||
|
||||
// Set to not visit one segment twice (stores road.id << X + segmentStart)
|
||||
VISITED_MAP visitedDirectSegments;
|
||||
VISITED_MAP visitedOppositeSegments;
|
||||
|
||||
// FIXME run recalculation
|
||||
bool runRecalculation = false;
|
||||
|
||||
// for start : f(start) = g(start) + h(start) = 0 + h(start) = h(start)
|
||||
int targetEndX = end->road->pointsX[end->segmentStart];
|
||||
int targetEndY = end->road->pointsY[end->segmentStart];
|
||||
int startX = start->road->pointsX[start->segmentStart];
|
||||
int startY = start->road->pointsY[start->segmentStart];
|
||||
float estimatedDistance = (float) h(ctx, targetEndX, targetEndY, startX, startY);
|
||||
end->distanceToEnd = start->distanceToEnd = estimatedDistance;
|
||||
|
||||
graphDirectSegments.push(start);
|
||||
graphReverseSegments.push(end);
|
||||
|
||||
// Extract & analyze segment with min(f(x)) from queue while final segment is not found
|
||||
bool inverse = false;
|
||||
bool init = false;
|
||||
|
||||
NonHeuristicSegmentsComparator nonHeuristicSegmentsComparator;
|
||||
SEGMENTS_QUEUE * graphSegments;
|
||||
if(inverse) {
|
||||
graphSegments = &graphReverseSegments;
|
||||
} else {
|
||||
graphSegments = &graphDirectSegments;
|
||||
}
|
||||
while (graphSegments->size() > 0) {
|
||||
SHARED_PTR<RouteSegment> segment = graphSegments->top();
|
||||
graphSegments->pop();
|
||||
bool routeFound = false;
|
||||
if (!inverse) {
|
||||
routeFound = processRouteSegment(ctx, false, graphDirectSegments, visitedDirectSegments, targetEndX, targetEndY,
|
||||
segment, visitedOppositeSegments);
|
||||
} else {
|
||||
routeFound = processRouteSegment(ctx, true, graphReverseSegments, visitedOppositeSegments, startX, startY, segment,
|
||||
visitedDirectSegments);
|
||||
}
|
||||
if(ctx->progress.get() && iterationsToUpdate-- < 0) {
|
||||
iterationsToUpdate = 100;
|
||||
ctx->progress->updateStatus(graphDirectSegments.empty()? 0 :graphDirectSegments.top()->distanceFromStart,
|
||||
graphDirectSegments.size(),
|
||||
graphReverseSegments.empty()? 0 :graphReverseSegments.top()->distanceFromStart,
|
||||
graphReverseSegments.size());
|
||||
if(ctx->progress->isCancelled()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (graphReverseSegments.size() == 0 || graphDirectSegments.size() == 0 || routeFound) {
|
||||
break;
|
||||
}
|
||||
if(runRecalculation) {
|
||||
// nothing to do
|
||||
inverse = false;
|
||||
} else if (!init) {
|
||||
inverse = !inverse;
|
||||
init = true;
|
||||
} else if (ctx->planRouteIn2Directions()) {
|
||||
inverse = !nonHeuristicSegmentsComparator(graphDirectSegments.top(), graphReverseSegments.top());
|
||||
if (graphDirectSegments.size() * 1.3 > graphReverseSegments.size()) {
|
||||
inverse = true;
|
||||
} else if (graphDirectSegments.size() < 1.3 * graphReverseSegments.size()) {
|
||||
inverse = false;
|
||||
}
|
||||
} else {
|
||||
// different strategy : use onedirectional graph
|
||||
inverse = ctx->getPlanRoadDirection() < 0;
|
||||
}
|
||||
if (inverse) {
|
||||
graphSegments = &graphReverseSegments;
|
||||
} else {
|
||||
graphSegments = &graphDirectSegments;
|
||||
}
|
||||
|
||||
// check if interrupted
|
||||
if(ctx->isInterrupted()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
ctx->timeToCalculate.pause();
|
||||
osmand_log_print(LOG_WARN, "[Native] Result visited (visited roads %d, visited segments %d / %d , queue sizes %d / %d ) ",
|
||||
ctx-> visitedSegments, visitedDirectSegments.size(), visitedOppositeSegments.size(),
|
||||
graphDirectSegments.size(),graphReverseSegments.size());
|
||||
osmand_log_print(LOG_WARN, "[Native] Result timing (time to load %d, time to calc %d, loaded tiles %d) ", ctx->timeToLoad.getElapsedTime()
|
||||
, ctx->timeToCalculate.getElapsedTime(), ctx->loadedTiles);
|
||||
int sz = calculateSizeOfSearchMaps(graphDirectSegments, graphReverseSegments, visitedDirectSegments, visitedOppositeSegments);
|
||||
osmand_log_print(LOG_WARN, "[Native] Memory occupied (Routing context %d Kb, search %d Kb)", ctx->getSize()/ 1024, sz/1024);
|
||||
}
|
||||
|
||||
bool processRouteSegment(RoutingContext* ctx, bool reverseWaySearch, SEGMENTS_QUEUE& graphSegments,
|
||||
VISITED_MAP& visitedSegments, int targetEndX, int targetEndY, SHARED_PTR<RouteSegment> segment, VISITED_MAP&oppositeSegments) {
|
||||
// Always start from segmentStart (!), not from segmentEnd
|
||||
// It makes difference only for the first start segment
|
||||
// Middle point will always be skipped from observation considering already visited
|
||||
SHARED_PTR<RouteDataObject> road = segment->road;
|
||||
int middle = segment->segmentStart;
|
||||
double obstaclePlusTime = 0;
|
||||
double obstacleMinusTime = 0;
|
||||
|
||||
// 0. mark route segment as visited
|
||||
int64_t nt = (road->id << ROUTE_POINTS) + middle;
|
||||
if(visitedSegments.find(nt) != visitedSegments.end()) {
|
||||
return false;
|
||||
}
|
||||
if(TRACE_ROUTING) {
|
||||
osmand_log_print(LOG_DEBUG, "Process segment id=%lld name=%s dist=%f", road->id, road->getName().c_str(), segment->distanceFromStart);
|
||||
}
|
||||
|
||||
ctx->visitedSegments++;
|
||||
// avoid empty segments to connect but mark the point as visited
|
||||
visitedSegments[nt] = SHARED_PTR<RouteSegment>();
|
||||
|
||||
int oneway = ctx->config.isOneWay(road);
|
||||
bool minusAllowed;
|
||||
bool plusAllowed;
|
||||
if(ctx->firstRoadId == nt) {
|
||||
if(ctx->firstRoadDirection < 0) {
|
||||
obstaclePlusTime += 500;
|
||||
} else if(ctx->firstRoadDirection > 0) {
|
||||
obstacleMinusTime += 500;
|
||||
}
|
||||
}
|
||||
if (!reverseWaySearch) {
|
||||
minusAllowed = oneway <= 0;
|
||||
plusAllowed = oneway >= 0;
|
||||
} else {
|
||||
minusAllowed = oneway >= 0;
|
||||
plusAllowed = oneway <= 0;
|
||||
}
|
||||
|
||||
// +/- diff from middle point
|
||||
int d = plusAllowed ? 1 : -1;
|
||||
if(segment->parentRoute.get() != NULL) {
|
||||
if(plusAllowed && middle < segment->road->pointsX.size() - 1) {
|
||||
obstaclePlusTime = ctx->config.calculateTurnTime(segment, segment->road->pointsX.size() - 1,
|
||||
segment->parentRoute, segment->parentSegmentEnd);
|
||||
}
|
||||
if(minusAllowed && middle > 0) {
|
||||
obstacleMinusTime = ctx->config.calculateTurnTime(segment, 0,
|
||||
segment->parentRoute, segment->parentSegmentEnd);
|
||||
}
|
||||
}
|
||||
// Go through all point of the way and find ways to continue
|
||||
// ! Actually there is small bug when there is restriction to move forward on way (it doesn't take into account)
|
||||
double posSegmentDist = 0;
|
||||
double negSegmentDist = 0;
|
||||
while (minusAllowed || plusAllowed) {
|
||||
// 1. calculate point not equal to middle
|
||||
// (algorithm should visit all point on way if it is not oneway)
|
||||
int segmentEnd = middle + d;
|
||||
bool positive = d > 0;
|
||||
if (!minusAllowed && d > 0) {
|
||||
d++;
|
||||
} else if (!plusAllowed && d < 0) {
|
||||
d--;
|
||||
} else {
|
||||
if (d <= 0) {
|
||||
d = -d + 1;
|
||||
} else {
|
||||
d = -d;
|
||||
}
|
||||
}
|
||||
if (segmentEnd < 0) {
|
||||
minusAllowed = false;
|
||||
continue;
|
||||
}
|
||||
if (segmentEnd >= road->pointsX.size()) {
|
||||
plusAllowed = false;
|
||||
continue;
|
||||
}
|
||||
// if we found end point break cycle
|
||||
int64_t nts = (road->id << ROUTE_POINTS) + segmentEnd;
|
||||
visitedSegments[nts]=segment;
|
||||
|
||||
// 2. calculate point and try to load neighbor ways if they are not loaded
|
||||
int x = road->pointsX[segmentEnd];
|
||||
int y = road->pointsY[segmentEnd];
|
||||
if(positive) {
|
||||
posSegmentDist += squareRootDist(x, y,
|
||||
road->pointsX[segmentEnd - 1], road->pointsY[segmentEnd - 1]);
|
||||
} else {
|
||||
negSegmentDist += squareRootDist(x, y,
|
||||
road->pointsX[segmentEnd + 1], road->pointsY[segmentEnd + 1]);
|
||||
}
|
||||
|
||||
// 2.1 calculate possible obstacle plus time
|
||||
if(positive) {
|
||||
double obstacle = ctx->config.defineRoutingObstacle(road, segmentEnd);
|
||||
if (obstacle < 0) {
|
||||
plusAllowed = false;
|
||||
continue;
|
||||
}
|
||||
obstaclePlusTime += obstacle;
|
||||
} else {
|
||||
double obstacle = ctx->config.defineRoutingObstacle(road, segmentEnd);
|
||||
if (obstacle < 0) {
|
||||
minusAllowed = false;
|
||||
continue;
|
||||
}
|
||||
obstacleMinusTime += obstacle;
|
||||
}
|
||||
// could be expensive calculation
|
||||
SHARED_PTR<RouteSegment> next = ctx->loadRouteSegment(x, y);
|
||||
// 3. get intersected ways
|
||||
if (next.get() != NULL) {
|
||||
if((next.get() == segment.get() || next->road->id == road->id) && next->next.get() == NULL) {
|
||||
// simplification if there is no real intersection
|
||||
continue;
|
||||
}
|
||||
|
||||
// Using A* routing algorithm
|
||||
// g(x) - calculate distance to that point and calculate time
|
||||
|
||||
double priority = ctx->config.defineSpeedPriority(road);
|
||||
double speed = ctx->config.defineSpeed(road) * priority;
|
||||
if (speed == 0) {
|
||||
speed = ctx->config.getMinDefaultSpeed() * priority;
|
||||
}
|
||||
double distOnRoadToPass = positive? posSegmentDist : negSegmentDist;
|
||||
double distStartObstacles = segment->distanceFromStart + ( positive ? obstaclePlusTime : obstacleMinusTime) + distOnRoadToPass / speed;
|
||||
|
||||
double distToFinalPoint = squareRootDist(x, y, targetEndX, targetEndY);
|
||||
bool routeFound = processIntersections(ctx, graphSegments, visitedSegments, oppositeSegments,
|
||||
distStartObstacles, distToFinalPoint, segment, segmentEnd, next, reverseWaySearch);
|
||||
if(routeFound) {
|
||||
return routeFound;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool proccessRestrictions(RoutingContext* ctx, SHARED_PTR<RouteDataObject> road, SHARED_PTR<RouteSegment> inputNext, bool reverseWay) {
|
||||
ctx->segmentsToVisitPrescripted.clear();
|
||||
ctx->segmentsToVisitNotForbidden.clear();
|
||||
bool exclusiveRestriction = false;
|
||||
SHARED_PTR<RouteSegment> next = inputNext;
|
||||
|
||||
if (!reverseWay && road->restrictions.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
if(!ctx->config.restrictionsAware()) {
|
||||
return false;
|
||||
}
|
||||
while (next.get() != NULL) {
|
||||
int type = -1;
|
||||
if (!reverseWay) {
|
||||
for (int i = 0; i < road->restrictions.size(); i++) {
|
||||
if ((road->restrictions[i] >> 3) == next->road->id) {
|
||||
type = road->restrictions[i] & 7;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < next->road->restrictions.size(); i++) {
|
||||
int rt = next->road->restrictions[i] & 7;
|
||||
int64_t restrictedTo = next->road->restrictions[i] >> 3;
|
||||
if (restrictedTo == road->id) {
|
||||
type = rt;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if there is restriction only to the other than current road
|
||||
if (rt == RESTRICTION_ONLY_RIGHT_TURN || rt == RESTRICTION_ONLY_LEFT_TURN
|
||||
|| rt == RESTRICTION_ONLY_STRAIGHT_ON) {
|
||||
// check if that restriction applies to considered junk
|
||||
SHARED_PTR<RouteSegment> foundNext = inputNext;
|
||||
while (foundNext.get() != NULL) {
|
||||
if (foundNext->road->id == restrictedTo) {
|
||||
break;
|
||||
}
|
||||
foundNext = foundNext->next;
|
||||
}
|
||||
if (foundNext.get() != NULL) {
|
||||
type = REVERSE_WAY_RESTRICTION_ONLY; // special constant
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type == REVERSE_WAY_RESTRICTION_ONLY) {
|
||||
// next = next.next; continue;
|
||||
} else if (type == -1 && exclusiveRestriction) {
|
||||
// next = next.next; continue;
|
||||
} else if (type == RESTRICTION_NO_LEFT_TURN || type == RESTRICTION_NO_RIGHT_TURN
|
||||
|| type == RESTRICTION_NO_STRAIGHT_ON || type == RESTRICTION_NO_U_TURN) {
|
||||
// next = next.next; continue;
|
||||
} else if (type == -1) {
|
||||
// case no restriction
|
||||
ctx->segmentsToVisitNotForbidden.push_back(next);
|
||||
} else {
|
||||
// case exclusive restriction (only_right, only_straight, ...)
|
||||
// 1. in case we are going backward we should not consider only_restriction
|
||||
// as exclusive because we have many "in" roads and one "out"
|
||||
// 2. in case we are going forward we have one "in" and many "out"
|
||||
if (!reverseWay) {
|
||||
exclusiveRestriction = true;
|
||||
ctx->segmentsToVisitNotForbidden.clear();
|
||||
ctx->segmentsToVisitPrescripted.push_back(next);
|
||||
} else {
|
||||
ctx->segmentsToVisitNotForbidden.push_back(next);
|
||||
}
|
||||
}
|
||||
next = next->next;
|
||||
}
|
||||
ctx->segmentsToVisitPrescripted.insert(ctx->segmentsToVisitPrescripted.end(), ctx->segmentsToVisitNotForbidden.begin(), ctx->segmentsToVisitNotForbidden.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool processIntersections(RoutingContext* ctx, SEGMENTS_QUEUE& graphSegments, VISITED_MAP& visitedSegments,
|
||||
VISITED_MAP& oppositeSegments, double distFromStart, double distToFinalPoint, SHARED_PTR<RouteSegment> segment,int segmentEnd, SHARED_PTR<RouteSegment> inputNext,
|
||||
bool reverseWay) {
|
||||
bool thereAreRestrictions = proccessRestrictions(ctx, segment->road, inputNext, reverseWay);
|
||||
vector<SHARED_PTR<RouteSegment> >::iterator nextIterator;
|
||||
if (thereAreRestrictions) {
|
||||
nextIterator = ctx->segmentsToVisitPrescripted.begin();
|
||||
}
|
||||
// Calculate possible ways to put into priority queue
|
||||
SHARED_PTR<RouteSegment> next = inputNext;
|
||||
bool hasNext = !thereAreRestrictions || nextIterator != ctx->segmentsToVisitPrescripted.end();
|
||||
while (hasNext) {
|
||||
if (thereAreRestrictions) {
|
||||
next = *nextIterator;
|
||||
}
|
||||
int64_t nts = (next->road->id << ROUTE_POINTS) + next->segmentStart;
|
||||
// 1. Check if opposite segment found so we can stop calculations
|
||||
if (oppositeSegments.find(nts) != oppositeSegments.end()) {
|
||||
// restrictions checked
|
||||
SHARED_PTR<RouteSegment> opposite = oppositeSegments[nts];
|
||||
// additional check if opposite way not the same as current one
|
||||
if (opposite.get() != NULL && (next->segmentStart != segmentEnd ||
|
||||
opposite->road->id != segment->road->id)) {
|
||||
SHARED_PTR<FinalRouteSegment> frs = SHARED_PTR<FinalRouteSegment>(new FinalRouteSegment);
|
||||
frs->direct = segment;
|
||||
frs->reverseWaySearch = reverseWay;
|
||||
SHARED_PTR<RouteSegment> op = SHARED_PTR<RouteSegment>(new RouteSegment(segment->road, segmentEnd));
|
||||
op->parentRoute = opposite;
|
||||
op->parentSegmentEnd = next->getSegmentStart();
|
||||
frs->opposite = op;
|
||||
frs->distanceFromStart = opposite->distanceFromStart + segment->distanceFromStart;
|
||||
ctx->finalRouteSegment = frs;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// road.id could be equal on roundabout, but we should accept them
|
||||
bool alreadyVisited = visitedSegments.find(nts) != visitedSegments.end();
|
||||
if (!alreadyVisited) {
|
||||
double distanceToEnd = h(ctx, distToFinalPoint, next);
|
||||
if (next->parentRoute.get() == NULL
|
||||
|| roadPriorityComparator(next->distanceFromStart, next->distanceToEnd, distFromStart, distanceToEnd,
|
||||
ctx->getHeuristicCoefficient()) > 0) {
|
||||
if (next->parentRoute.get() != NULL) {
|
||||
// already in queue remove it (we can not remove it)
|
||||
next = SHARED_PTR<RouteSegment>(new RouteSegment(next->road, next->segmentStart));
|
||||
}
|
||||
next->distanceFromStart = distFromStart;
|
||||
next->distanceToEnd = distanceToEnd;
|
||||
// put additional information to recover whole route after
|
||||
next->parentRoute = segment;
|
||||
next->parentSegmentEnd = segmentEnd;
|
||||
if(TRACE_ROUTING) {
|
||||
osmand_log_print(LOG_DEBUG, ">> next segment id=%lld name=%s dist=%f", next->road->id, next->road->getName().c_str(), next->distanceFromStart);
|
||||
}
|
||||
graphSegments.push(next);
|
||||
}
|
||||
} else {
|
||||
// the segment was already visited! We need to follow better route if it exists
|
||||
// that is very strange situation and almost exception (it can happen when we underestimate distnceToEnd)
|
||||
if (distFromStart < next->distanceFromStart && next->road->id != segment->road->id) {
|
||||
next->distanceFromStart = distFromStart;
|
||||
next->parentRoute = segment;
|
||||
next->parentSegmentEnd = segmentEnd;
|
||||
}
|
||||
}
|
||||
|
||||
// iterate to next road
|
||||
if (thereAreRestrictions) {
|
||||
nextIterator++;
|
||||
hasNext = nextIterator != ctx->segmentsToVisitPrescripted.end();
|
||||
} else {
|
||||
next = next->next;
|
||||
hasNext = next.get() != NULL;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SHARED_PTR<RouteSegment> findRouteSegment(int px, int py, RoutingContext* ctx) {
|
||||
vector<SHARED_PTR<RouteDataObject> > dataObjects;
|
||||
ctx->loadTileData(px, py, 17, dataObjects);
|
||||
if (dataObjects.size() == 0) {
|
||||
ctx->loadTileData(px, py, 15, dataObjects);
|
||||
}
|
||||
SHARED_PTR<RouteSegment> road;
|
||||
double sdist = 0;
|
||||
int foundx = 0;
|
||||
int foundy = 0;
|
||||
vector<SHARED_PTR<RouteDataObject> >::iterator it = dataObjects.begin();
|
||||
for (; it!= dataObjects.end(); it++) {
|
||||
SHARED_PTR<RouteDataObject> r = *it;
|
||||
if (r->pointsX.size() > 1) {
|
||||
for (int j = 1; j < r->pointsX.size(); j++) {
|
||||
double mDist = squareRootDist(r->pointsX[j -1 ], r->pointsY[j-1], r->pointsX[j], r->pointsY[j]);
|
||||
int prx = r->pointsX[j];
|
||||
int pry = r->pointsY[j];
|
||||
double projection = calculateProjection31TileMetric(r->pointsX[j -1 ], r->pointsY[j-1], r->pointsX[j], r->pointsY[j],
|
||||
px, py);
|
||||
if (projection < 0) {
|
||||
prx = r->pointsX[j - 1];
|
||||
pry = r->pointsY[j - 1];
|
||||
} else if (projection >= mDist * mDist) {
|
||||
prx = r->pointsX[j ];
|
||||
pry = r->pointsY[j ];
|
||||
} else {
|
||||
double c = projection / (mDist * mDist);
|
||||
prx = (int) ((double)r->pointsX[j - 1] + ((double)r->pointsX[j] - r->pointsX[j - 1]) * c);
|
||||
pry = (int) ((double)r->pointsY[j - 1] + ((double)r->pointsY[j] - r->pointsY[j - 1]) * c);
|
||||
}
|
||||
double currentsDist = squareDist31TileMetric(prx, pry, px, py);
|
||||
if (road.get() == NULL || currentsDist < sdist) {
|
||||
road = SHARED_PTR<RouteSegment>(new RouteSegment(r, j));
|
||||
foundx = prx;
|
||||
foundy = pry;
|
||||
sdist = currentsDist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (road.get() != NULL) {
|
||||
// make copy before
|
||||
SHARED_PTR<RouteDataObject> r = road->road;
|
||||
int index = road->getSegmentStart();
|
||||
r->pointsX.insert(r->pointsX.begin() + index, foundx);
|
||||
r->pointsY.insert(r->pointsY.begin() + index, foundy);
|
||||
if(r->pointTypes.size() > index) {
|
||||
r->pointTypes.insert(r->pointTypes.begin() + index, std::vector<uint32_t>());
|
||||
}
|
||||
}
|
||||
return road;
|
||||
}
|
||||
|
||||
bool combineTwoSegmentResult(RouteSegmentResult& toAdd, RouteSegmentResult& previous, bool reverse) {
|
||||
bool ld = previous.endPointIndex > previous.startPointIndex;
|
||||
bool rd = toAdd.endPointIndex > toAdd.startPointIndex;
|
||||
if (rd == ld) {
|
||||
if (toAdd.startPointIndex == previous.endPointIndex && !reverse) {
|
||||
previous.endPointIndex = toAdd.endPointIndex;
|
||||
return true;
|
||||
} else if (toAdd.endPointIndex == previous.startPointIndex && reverse) {
|
||||
previous.startPointIndex = toAdd.startPointIndex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void addRouteSegmentToResult(vector<RouteSegmentResult>& result, RouteSegmentResult& res, bool reverse) {
|
||||
if (res.endPointIndex != res.startPointIndex) {
|
||||
if (result.size() > 0) {
|
||||
RouteSegmentResult last = result[result.size() - 1];
|
||||
if (last.object->id == res.object->id) {
|
||||
if (combineTwoSegmentResult(res, last, reverse)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
result.push_back(res);
|
||||
}
|
||||
}
|
||||
|
||||
void attachConnectedRoads(RoutingContext* ctx, vector<RouteSegmentResult>& res) {
|
||||
vector<RouteSegmentResult>::iterator it = res.begin();
|
||||
for (; it != res.end(); it++) {
|
||||
bool plus = it->startPointIndex < it->endPointIndex;
|
||||
int j = it->startPointIndex;
|
||||
do {
|
||||
SHARED_PTR<RouteSegment> s = ctx->loadRouteSegment(it->object->pointsX[j], it->object->pointsY[j]);
|
||||
vector<RouteSegmentResult> r;
|
||||
RouteSegment* rs = s.get();
|
||||
while(rs != NULL) {
|
||||
RouteSegmentResult res(rs->road, rs->getSegmentStart(), rs->getSegmentStart());
|
||||
r.push_back(res);
|
||||
rs = rs->next.get();
|
||||
}
|
||||
it->attachedRoutes.push_back(r);
|
||||
j = plus ? j + 1 : j - 1;
|
||||
}while(j != it->endPointIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vector<RouteSegmentResult> convertFinalSegmentToResults(RoutingContext* ctx) {
|
||||
vector<RouteSegmentResult> result;
|
||||
if (ctx->finalRouteSegment.get() != NULL) {
|
||||
osmand_log_print(LOG_INFO, "Routing calculated time distance %f", ctx->finalRouteSegment->distanceFromStart);
|
||||
SHARED_PTR<FinalRouteSegment> finalSegment = ctx->finalRouteSegment;
|
||||
// Get results from opposite direction roads
|
||||
SHARED_PTR<RouteSegment> segment = finalSegment->reverseWaySearch ? finalSegment->direct : finalSegment->opposite->parentRoute;
|
||||
int parentSegmentStart =
|
||||
finalSegment->reverseWaySearch ?
|
||||
finalSegment->opposite->getSegmentStart() : finalSegment->opposite->parentSegmentEnd;
|
||||
while (segment.get() != NULL) {
|
||||
RouteSegmentResult res(segment->road, parentSegmentStart, segment->getSegmentStart());
|
||||
parentSegmentStart = segment->parentSegmentEnd;
|
||||
segment = segment->parentRoute;
|
||||
addRouteSegmentToResult(result, res, false);
|
||||
}
|
||||
// reverse it just to attach good direction roads
|
||||
std::reverse(result.begin(), result.end());
|
||||
|
||||
segment = finalSegment->reverseWaySearch ? finalSegment->opposite->parentRoute : finalSegment->direct;
|
||||
int parentSegmentEnd =
|
||||
finalSegment->reverseWaySearch ?
|
||||
finalSegment->opposite->parentSegmentEnd : finalSegment->opposite->getSegmentStart();
|
||||
|
||||
while (segment.get() != NULL) {
|
||||
RouteSegmentResult res(segment->road, segment->getSegmentStart(), parentSegmentEnd);
|
||||
parentSegmentEnd = segment->parentSegmentEnd;
|
||||
segment = segment->parentRoute;
|
||||
// happens in smart recalculation
|
||||
addRouteSegmentToResult(result, res, true);
|
||||
}
|
||||
std::reverse(result.begin(), result.end());
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<RouteSegmentResult> searchRouteInternal(RoutingContext* ctx, bool leftSideNavigation) {
|
||||
SHARED_PTR<RouteSegment> start = findRouteSegment(ctx->startX, ctx->startY, ctx);
|
||||
if(start.get() == NULL) {
|
||||
osmand_log_print(LOG_WARN, "Start point was not found [Native]");
|
||||
if(ctx->progress.get()) {
|
||||
ctx->progress->setSegmentNotFound(0);
|
||||
}
|
||||
return vector<RouteSegmentResult>();
|
||||
} else {
|
||||
osmand_log_print(LOG_WARN, "Start point was found %lld [Native]", start->road->id);
|
||||
}
|
||||
SHARED_PTR<RouteSegment> end = findRouteSegment(ctx->endX, ctx->endY, ctx);
|
||||
if(end.get() == NULL) {
|
||||
if(ctx->progress.get()) {
|
||||
ctx->progress->setSegmentNotFound(1);
|
||||
}
|
||||
osmand_log_print(LOG_WARN, "End point was not found [Native]");
|
||||
return vector<RouteSegmentResult>();
|
||||
} else {
|
||||
osmand_log_print(LOG_WARN, "End point was found %lld [Native]", end->road->id);
|
||||
}
|
||||
searchRouteInternal(ctx, start, end, leftSideNavigation);
|
||||
vector<RouteSegmentResult> res = convertFinalSegmentToResults(ctx);
|
||||
attachConnectedRoads(ctx, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool compareRoutingSubregionTile(SHARED_PTR<RoutingSubregionTile> o1, SHARED_PTR<RoutingSubregionTile> o2) {
|
||||
int v1 = (o1->access + 1) * pow((float)10, o1->getUnloadCount() -1);
|
||||
int v2 = (o2->access + 1) * pow((float)10, o2->getUnloadCount() -1);
|
||||
return v1 < v2;
|
||||
}
|
|
@ -1,626 +0,0 @@
|
|||
#ifndef _OSMAND_BINARY_ROUTE_PLANNER_H
|
||||
#define _OSMAND_BINARY_ROUTE_PLANNER_H
|
||||
#include "common.h"
|
||||
#include "binaryRead.h"
|
||||
#include <algorithm>
|
||||
|
||||
typedef UNORDERED(map)<string, float> MAP_STR_FLOAT;
|
||||
typedef UNORDERED(map)<string, string> MAP_STR_STR;
|
||||
|
||||
static double measuredDist(int x1, int y1, int x2, int y2) {
|
||||
return getDistance(get31LatitudeY(y1), get31LongitudeX(x1), get31LatitudeY(y2),
|
||||
get31LongitudeX(x2));
|
||||
}
|
||||
|
||||
struct RouteSegment {
|
||||
public :
|
||||
int segmentStart;
|
||||
SHARED_PTR<RouteDataObject> road;
|
||||
// needed to store intersection of routes
|
||||
SHARED_PTR<RouteSegment> next;
|
||||
|
||||
// search context (needed for searching route)
|
||||
// Initially it should be null (!) because it checks was it segment visited before
|
||||
SHARED_PTR<RouteSegment> parentRoute;
|
||||
int parentSegmentEnd;
|
||||
|
||||
// distance measured in time (seconds)
|
||||
float distanceFromStart;
|
||||
float distanceToEnd;
|
||||
|
||||
inline int getSegmentStart() {
|
||||
return segmentStart;
|
||||
}
|
||||
|
||||
RouteSegment(SHARED_PTR<RouteDataObject> road, int segmentStart) : road(road), segmentStart(segmentStart),
|
||||
parentSegmentEnd(0), distanceFromStart(0), distanceToEnd(0),next(), parentRoute(){
|
||||
}
|
||||
~RouteSegment(){
|
||||
}
|
||||
};
|
||||
|
||||
struct RouteSegmentResult {
|
||||
SHARED_PTR<RouteDataObject> object;
|
||||
int startPointIndex;
|
||||
int endPointIndex;
|
||||
vector<vector<RouteSegmentResult> > attachedRoutes;
|
||||
RouteSegmentResult(SHARED_PTR<RouteDataObject> object, int startPointIndex, int endPointIndex) :
|
||||
object(object), startPointIndex(startPointIndex), endPointIndex (endPointIndex) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
struct FinalRouteSegment {
|
||||
SHARED_PTR<RouteSegment> direct;
|
||||
bool reverseWaySearch;
|
||||
SHARED_PTR<RouteSegment> opposite;
|
||||
float distanceFromStart;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct RoutingSubregionTile {
|
||||
RouteSubregion subregion;
|
||||
// make it without get/set for fast access
|
||||
int access;
|
||||
int loaded;
|
||||
int size ;
|
||||
UNORDERED(map)<int64_t, SHARED_PTR<RouteSegment> > routes;
|
||||
|
||||
RoutingSubregionTile(RouteSubregion& sub) : access(0), loaded(0), subregion(sub) {
|
||||
size = sizeof(RoutingSubregionTile);
|
||||
}
|
||||
~RoutingSubregionTile(){
|
||||
}
|
||||
bool isLoaded(){
|
||||
return loaded > 0;
|
||||
}
|
||||
|
||||
void setLoaded(){
|
||||
loaded = abs(loaded) + 1;
|
||||
}
|
||||
|
||||
void unload(){
|
||||
routes.clear();
|
||||
size = 0;
|
||||
loaded = - abs(loaded);
|
||||
}
|
||||
|
||||
int getUnloadCount() {
|
||||
return abs(loaded);
|
||||
}
|
||||
|
||||
int getSize(){
|
||||
return size + routes.size() * sizeof(std::pair<int64_t, SHARED_PTR<RouteSegment> >);
|
||||
}
|
||||
|
||||
void add(SHARED_PTR<RouteDataObject> o) {
|
||||
size += o->getSize() + sizeof(RouteSegment)* o->pointsX.size();
|
||||
for (int i = 0; i < o->pointsX.size(); i++) {
|
||||
uint64_t x31 = o->pointsX[i];
|
||||
uint64_t y31 = o->pointsY[i];
|
||||
uint64_t l = (((uint64_t) x31) << 31) + (uint64_t) y31;
|
||||
SHARED_PTR<RouteSegment> segment = SHARED_PTR<RouteSegment>(new RouteSegment(o, i));
|
||||
if (routes[l].get() == NULL) {
|
||||
routes[l] = segment;
|
||||
} else {
|
||||
SHARED_PTR<RouteSegment> orig = routes[l];
|
||||
int cnt = 0;
|
||||
while (orig->next.get() != NULL) {
|
||||
orig = orig->next;
|
||||
cnt++;
|
||||
}
|
||||
orig->next = segment;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
static int64_t calcRouteId(SHARED_PTR<RouteDataObject> o, int ind) {
|
||||
return ((int64_t) o->id << 10) + ind;
|
||||
}
|
||||
|
||||
typedef std::pair<int, std::pair<string, string> > ROUTE_TRIPLE;
|
||||
struct RoutingConfiguration {
|
||||
// 0 index in triple
|
||||
MAP_STR_FLOAT highwaySpeed ;
|
||||
// 1 index in triple
|
||||
MAP_STR_FLOAT highwayPriorities ;
|
||||
// 2 index in triple
|
||||
MAP_STR_FLOAT avoid ;
|
||||
// 3 index in triple
|
||||
MAP_STR_FLOAT obstacles;
|
||||
// 4 index in triple
|
||||
MAP_STR_FLOAT routingObstacles;
|
||||
// 5 index in triple
|
||||
MAP_STR_STR attributes;
|
||||
|
||||
int zoomToLoad;
|
||||
float heurCoefficient;
|
||||
float maxDefaultSpeed;
|
||||
float minDefaultSpeed;
|
||||
bool restrictions;
|
||||
bool onewayAware;
|
||||
bool followLimitations;
|
||||
int memoryLimitation;
|
||||
int planRoadDirection;
|
||||
string routerName;
|
||||
float initialDirection;
|
||||
float distanceRecalculate;
|
||||
string routerProfile;
|
||||
float roundaboutTurn;
|
||||
float leftTurn;
|
||||
float rightTurn;
|
||||
|
||||
float parseFloat(string key, float def) {
|
||||
if(attributes.find(key) != attributes.end() && attributes[key] != "") {
|
||||
return atof(attributes[key].c_str());
|
||||
}
|
||||
return def;
|
||||
}
|
||||
bool parseBool(string key, bool def) {
|
||||
if (attributes.find(key) != attributes.end() && attributes[key] != "") {
|
||||
return attributes[key] == "true";
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
string parseString(string key, string def) {
|
||||
if (attributes.find(key) != attributes.end() && attributes[key] != "") {
|
||||
return attributes[key];
|
||||
}
|
||||
return def;
|
||||
}
|
||||
void defaultParams() {
|
||||
planRoadDirection = (int) parseFloat("planRoadDirection", 0);
|
||||
restrictions = parseBool("restrictionsAware", true);
|
||||
followLimitations = parseBool("followSpeedLimitations", true);
|
||||
onewayAware = parseBool("onewayAware", true);
|
||||
roundaboutTurn = parseFloat("roundaboutTurn", 0);
|
||||
leftTurn = parseFloat("leftTurn", 0);
|
||||
rightTurn = parseFloat("rightTurn", 0);
|
||||
minDefaultSpeed = parseFloat("minDefaultSpeed", 45) / 3.6;
|
||||
maxDefaultSpeed = parseFloat("maxDefaultSpeed", 130) / 3.6;
|
||||
heurCoefficient = parseFloat("heuristicCoefficient", 1);
|
||||
// don't use file limitations?
|
||||
memoryLimitation = (int)parseFloat("nativeMemoryLimitInMB", memoryLimitation);
|
||||
zoomToLoad = (int)parseFloat("zoomToLoadTiles", 16);
|
||||
routerName = parseString("name", "default");
|
||||
routerProfile = parseString("baseProfile", "car");
|
||||
distanceRecalculate = parseFloat("recalculateDistanceHelp", 10000) ;
|
||||
}
|
||||
|
||||
RoutingConfiguration(vector<ROUTE_TRIPLE>& config, float initDirection = -360, int memLimit = 48) :
|
||||
memoryLimitation(memLimit), initialDirection(initDirection) {
|
||||
for(int j = 0; j<config.size(); j++) {
|
||||
ROUTE_TRIPLE r = config[j];
|
||||
if(r.first == 0) {
|
||||
highwaySpeed[r.second.first] = atof(r.second.second.c_str());
|
||||
} else if(r.first == 1) {
|
||||
highwayPriorities[r.second.first] = atof(r.second.second.c_str());
|
||||
} else if(r.first == 2) {
|
||||
avoid[r.second.first] = atof(r.second.second.c_str());
|
||||
} else if(r.first == 3) {
|
||||
obstacles[r.second.first] = atof(r.second.second.c_str());
|
||||
} else if(r.first == 4) {
|
||||
routingObstacles[r.second.first] = atof(r.second.second.c_str());
|
||||
} else if(r.first == 5) {
|
||||
string v = r.second.second;
|
||||
attributes[r.second.first] = v;
|
||||
}
|
||||
}
|
||||
defaultParams();
|
||||
}
|
||||
|
||||
bool acceptLine(SHARED_PTR<RouteDataObject> r) {
|
||||
std::vector<uint32_t>::iterator t = r->types.begin();
|
||||
bool accepted = false;
|
||||
for(; t != r->types.end(); t++) {
|
||||
tag_value type = r->region->decodingRules[*t];
|
||||
if(type.first=="highway" && highwaySpeed[type.second] > 0) {
|
||||
accepted = true;
|
||||
break;
|
||||
} else if(highwaySpeed[type.first + '$' + type.second] > 0) {
|
||||
accepted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!accepted) {
|
||||
return false;
|
||||
}
|
||||
t = r->types.begin();
|
||||
for(; t != r->types.end(); t++) {
|
||||
tag_value type = r->region->decodingRules[*t];
|
||||
if(avoid.find(type.first + '$' + type.second) != avoid.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string getHighway(SHARED_PTR<RouteDataObject> r) {
|
||||
std::vector<uint32_t>::iterator t = r->types.begin();
|
||||
for(; t != r->types.end(); t++) {
|
||||
tag_value type = r->region->decodingRules[*t];
|
||||
if(type.first=="highway") {
|
||||
return type.second;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
float defineSpeedPriority(SHARED_PTR<RouteDataObject> r) {
|
||||
float priority = 1;
|
||||
std::vector<uint32_t>::iterator t = r->types.begin();
|
||||
for(; t != r->types.end(); t++) {
|
||||
tag_value type = r->region->decodingRules[*t];
|
||||
if(highwayPriorities.find(type.first+"$"+type.second) != highwaySpeed.end()) {
|
||||
priority *= highwayPriorities[type.first+"$"+type.second];
|
||||
}
|
||||
}
|
||||
return priority;
|
||||
}
|
||||
|
||||
float getMinDefaultSpeed() {
|
||||
return minDefaultSpeed;
|
||||
}
|
||||
float getMaxDefaultSpeed() {
|
||||
return maxDefaultSpeed;
|
||||
}
|
||||
|
||||
int isOneWay(SHARED_PTR<RouteDataObject> r) {
|
||||
if(!onewayAware){
|
||||
return 0;
|
||||
}
|
||||
std::vector<uint32_t>::iterator t = r->types.begin();
|
||||
for(; t != r->types.end(); t++) {
|
||||
tag_value type = r->region->decodingRules[*t];
|
||||
if(type.first == "oneway") {
|
||||
string v = type.second;
|
||||
if("-1" ==v || "reverse" == v) {
|
||||
return -1;
|
||||
} else if("1" == v || "yes" == v) {
|
||||
return 1;
|
||||
}
|
||||
} else if(type.first == "roundabout") {
|
||||
return 1;
|
||||
} else if(type.first == "junction" && type.second == "roundabout") {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO FIX
|
||||
float calculateTurnTime(SHARED_PTR<RouteSegment> segment, int index, SHARED_PTR<RouteSegment> next, int nextIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float defineRoutingObstacle(SHARED_PTR<RouteDataObject> road, int segmentEnd) {
|
||||
if(road->pointTypes.size() <= segmentEnd) {
|
||||
return 0;
|
||||
}
|
||||
std::vector<uint32_t> pointTypes = road->pointTypes[segmentEnd];
|
||||
std::vector<uint32_t>::iterator t = pointTypes.begin();
|
||||
for(; t != pointTypes.end(); t++) {
|
||||
tag_value type = road->region->decodingRules[*t];
|
||||
if(routingObstacles.find(type.first + "$" + type.second) != routingObstacles.end()) {
|
||||
return routingObstacles[type.first + "$" + type.second];
|
||||
}
|
||||
}
|
||||
t = pointTypes.begin();
|
||||
for(; t != pointTypes.end(); t++) {
|
||||
tag_value type = road->region->decodingRules[*t];
|
||||
if(routingObstacles.find(type.first + "$" ) != routingObstacles.end()) {
|
||||
return routingObstacles[type.first + "$" ];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool restrictionsAware() {
|
||||
return restrictions;
|
||||
}
|
||||
|
||||
float maxSpeed(SHARED_PTR<RouteDataObject> r) {
|
||||
std::vector<uint32_t>::iterator t = r->types.begin();
|
||||
for(; t != r->types.end(); t++) {
|
||||
tag_value type = r->region->decodingRules[*t];
|
||||
if(type.first=="maxspeed") {
|
||||
std::string v = type.second;
|
||||
int i = 0;
|
||||
while(i < v.length() && v[i] >= '0' && v[i] <= '9') {
|
||||
i++;
|
||||
}
|
||||
if(i > 0) {
|
||||
float f = atoi(v.substr(0, i).c_str());
|
||||
f = f / 3.6;
|
||||
if(v.find("mph") != std::string::npos ) {
|
||||
f *= 1.6;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float defineSpeed(SHARED_PTR<RouteDataObject> r) {
|
||||
if (followLimitations) {
|
||||
float m = maxSpeed(r);
|
||||
if(m > 0) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
std::vector<uint32_t>::iterator t = r->types.begin();
|
||||
for(; t != r->types.end(); t++) {
|
||||
tag_value type = r->region->decodingRules[*t];
|
||||
if(highwaySpeed.find(type.first+"$"+type.second) != highwaySpeed.end()) {
|
||||
return highwaySpeed[type.first+"$"+type.second] / 3.6;
|
||||
}
|
||||
}
|
||||
return getMinDefaultSpeed();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
bool compareRoutingSubregionTile(SHARED_PTR<RoutingSubregionTile> o1, SHARED_PTR<RoutingSubregionTile> o2);
|
||||
|
||||
class RouteCalculationProgress {
|
||||
protected:
|
||||
int segmentNotFound ;
|
||||
float distanceFromBegin;
|
||||
int directSegmentQueueSize;
|
||||
float distanceFromEnd;
|
||||
int reverseSegmentQueueSize;
|
||||
|
||||
bool cancelled;
|
||||
public:
|
||||
RouteCalculationProgress() : segmentNotFound(-1), distanceFromBegin(0),
|
||||
distanceFromEnd(0), directSegmentQueueSize(0), reverseSegmentQueueSize(0), cancelled(false){
|
||||
}
|
||||
|
||||
virtual bool isCancelled(){
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
virtual void setSegmentNotFound(int s){
|
||||
segmentNotFound = s;
|
||||
}
|
||||
|
||||
virtual void updateStatus(float distanceFromBegin, int directSegmentQueueSize, float distanceFromEnd,
|
||||
int reverseSegmentQueueSize) {
|
||||
this->distanceFromBegin = max(distanceFromBegin, this->distanceFromBegin );
|
||||
this->distanceFromEnd = max(distanceFromEnd,this->distanceFromEnd);
|
||||
this->directSegmentQueueSize = directSegmentQueueSize;
|
||||
this->reverseSegmentQueueSize = reverseSegmentQueueSize;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct RoutingContext {
|
||||
typedef UNORDERED(map)<int64_t, SHARED_PTR<RoutingSubregionTile> > MAP_SUBREGION_TILES;
|
||||
|
||||
int visitedSegments;
|
||||
int loadedTiles;
|
||||
ElapsedTimer timeToLoad;
|
||||
ElapsedTimer timeToCalculate;
|
||||
int firstRoadDirection;
|
||||
int64_t firstRoadId;
|
||||
RoutingConfiguration config;
|
||||
SHARED_PTR<RouteCalculationProgress> progress;
|
||||
|
||||
int gcCollectIterations;
|
||||
|
||||
int startX;
|
||||
int startY;
|
||||
int endX;
|
||||
int endY;
|
||||
|
||||
vector<SHARED_PTR<RouteSegment> > segmentsToVisitNotForbidden;
|
||||
vector<SHARED_PTR<RouteSegment> > segmentsToVisitPrescripted;
|
||||
|
||||
SHARED_PTR<FinalRouteSegment> finalRouteSegment;
|
||||
MAP_SUBREGION_TILES subregionTiles;
|
||||
UNORDERED(map)<int64_t, std::vector<SHARED_PTR<RoutingSubregionTile> > > indexedSubregions;
|
||||
|
||||
RoutingContext(RoutingConfiguration& config) : finalRouteSegment(), firstRoadDirection(0),firstRoadId(0),
|
||||
loadedTiles(0), visitedSegments(0), config(config){
|
||||
}
|
||||
|
||||
bool acceptLine(SHARED_PTR<RouteDataObject> r) {
|
||||
return config.acceptLine(r);
|
||||
}
|
||||
|
||||
int getSize() {
|
||||
// multiply 2 for to maps
|
||||
int sz = subregionTiles.size() * sizeof(pair< int64_t, SHARED_PTR<RoutingSubregionTile> >) * 2;
|
||||
MAP_SUBREGION_TILES::iterator it = subregionTiles.begin();
|
||||
for(;it != subregionTiles.end(); it++) {
|
||||
sz += it->second->getSize();
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
void unloadUnusedTiles(int memoryLimit) {
|
||||
int sz = getSize();
|
||||
float critical = 0.9f * memoryLimit * 1024 * 1024;
|
||||
if(sz < critical) {
|
||||
return;
|
||||
}
|
||||
float occupiedBefore = sz / (1024. * 1024.);
|
||||
float desirableSize = memoryLimit * 0.7f * 1024 * 1024;
|
||||
vector<SHARED_PTR<RoutingSubregionTile> > list;
|
||||
MAP_SUBREGION_TILES::iterator it = subregionTiles.begin();
|
||||
int loaded = 0;
|
||||
int unloadedTiles = 0;
|
||||
for(;it != subregionTiles.end(); it++) {
|
||||
if(it->second->isLoaded()) {
|
||||
list.push_back(it->second);
|
||||
loaded++;
|
||||
}
|
||||
}
|
||||
sort(list.begin(), list.end(), compareRoutingSubregionTile);
|
||||
int i =0;
|
||||
while(sz >= desirableSize && i < list.size()) {
|
||||
SHARED_PTR<RoutingSubregionTile> unload = list[i];
|
||||
i++;
|
||||
sz -= unload->getSize();
|
||||
unload->unload();
|
||||
unloadedTiles ++;
|
||||
}
|
||||
for(i = 0; i<list.size(); i++) {
|
||||
list[i]->access /= 3;
|
||||
}
|
||||
osmand_log_print(LOG_INFO, "Run GC (before %f Mb after %f Mb) unload %d of %d tiles",
|
||||
occupiedBefore, getSize() / (1024.0*1024.0),
|
||||
unloadedTiles, loaded);
|
||||
}
|
||||
|
||||
void loadHeaderObjects(int64_t tileId) {
|
||||
vector<SHARED_PTR<RoutingSubregionTile> >& subregions = indexedSubregions[tileId];
|
||||
bool gc = false;
|
||||
for(int j = 0; j<subregions.size() && !gc; j++) {
|
||||
if(!subregions[j]->isLoaded()) {
|
||||
gc = true;
|
||||
}
|
||||
}
|
||||
if(gc) {
|
||||
unloadUnusedTiles(config.memoryLimitation);
|
||||
}
|
||||
for(int j = 0; j<subregions.size(); j++) {
|
||||
if(!subregions[j]->isLoaded()) {
|
||||
loadedTiles++;
|
||||
subregions[j]->setLoaded();
|
||||
SearchQuery q;
|
||||
vector<RouteDataObject*> res;
|
||||
searchRouteDataForSubRegion(&q, res, &subregions[j]->subregion);
|
||||
vector<RouteDataObject*>::iterator i = res.begin();
|
||||
for(;i!=res.end(); i++) {
|
||||
if(*i != NULL) {
|
||||
SHARED_PTR<RouteDataObject> o(*i);
|
||||
if(acceptLine(o)) {
|
||||
subregions[j]->add(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loadHeaders(uint32_t xloc, uint32_t yloc) {
|
||||
timeToLoad.start();
|
||||
int z = config.zoomToLoad;
|
||||
int tz = 31 - z;
|
||||
int64_t tileId = (xloc << z) + yloc;
|
||||
if (indexedSubregions.find(tileId) == indexedSubregions.end()) {
|
||||
SearchQuery q((uint32_t) (xloc << tz),
|
||||
(uint32_t) ((xloc + 1) << tz), (uint32_t) (yloc << tz), (uint32_t) ((yloc + 1) << tz));
|
||||
std::vector<RouteSubregion> tempResult;
|
||||
searchRouteSubregions(&q, tempResult);
|
||||
std::vector<SHARED_PTR<RoutingSubregionTile> > collection;
|
||||
for(int i=0; i<tempResult.size(); i++) {
|
||||
RouteSubregion& rs = tempResult[i];
|
||||
int64_t key = ((int64_t)rs.left << 31)+ rs.filePointer;
|
||||
if(subregionTiles.find(key) == subregionTiles.end()) {
|
||||
subregionTiles[key] = SHARED_PTR<RoutingSubregionTile>(new RoutingSubregionTile(rs));
|
||||
}
|
||||
collection.push_back(subregionTiles[key]);
|
||||
}
|
||||
indexedSubregions[tileId] = collection;
|
||||
}
|
||||
loadHeaderObjects(tileId);
|
||||
timeToLoad.pause();
|
||||
}
|
||||
|
||||
void loadTileData(int x31, int y31, int zoomAround, vector<SHARED_PTR<RouteDataObject> >& dataObjects ) {
|
||||
int t = config.zoomToLoad - zoomAround;
|
||||
int coordinatesShift = (1 << (31 - config.zoomToLoad));
|
||||
if(t <= 0) {
|
||||
t = 1;
|
||||
coordinatesShift = (1 << (31 - zoomAround));
|
||||
} else {
|
||||
t = 1 << t;
|
||||
}
|
||||
UNORDERED(set)<int64_t> ids;
|
||||
int z = config.zoomToLoad;
|
||||
for(int i = -t; i <= t; i++) {
|
||||
for(int j = -t; j <= t; j++) {
|
||||
uint32_t xloc = (x31 + i*coordinatesShift) >> (31 - z);
|
||||
uint32_t yloc = (y31+j*coordinatesShift) >> (31 - z);
|
||||
int64_t tileId = (xloc << z) + yloc;
|
||||
loadHeaders(xloc, yloc);
|
||||
vector<SHARED_PTR<RoutingSubregionTile> >& subregions = indexedSubregions[tileId];
|
||||
for(int j = 0; j<subregions.size(); j++) {
|
||||
if(subregions[j]->isLoaded()) {
|
||||
UNORDERED(map)<int64_t, SHARED_PTR<RouteSegment> >::iterator s = subregions[j]->routes.begin();
|
||||
while(s != subregions[j]->routes.end()) {
|
||||
SHARED_PTR<RouteSegment> seg = s->second;
|
||||
if(seg.get() != NULL) {
|
||||
if(ids.find(seg->road->id) == ids.end()) {
|
||||
dataObjects.push_back(seg->road);
|
||||
ids.insert(seg->road->id);
|
||||
}
|
||||
seg = seg->next;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// void searchRouteRegion(SearchQuery* q, std::vector<RouteDataObject*>& list, RoutingIndex* rs, RouteSubregion* sub)
|
||||
SHARED_PTR<RouteSegment> loadRouteSegment(int x31, int y31) {
|
||||
int z = config.zoomToLoad;
|
||||
int64_t xloc = x31 >> (31 - z);
|
||||
int64_t yloc = y31 >> (31 - z);
|
||||
uint64_t l = (((uint64_t) x31) << 31) + (uint64_t) y31;
|
||||
int64_t tileId = (xloc << z) + yloc;
|
||||
loadHeaders(xloc, yloc);
|
||||
vector<SHARED_PTR<RoutingSubregionTile> >& subregions = indexedSubregions[tileId];
|
||||
UNORDERED(map)<int64_t, SHARED_PTR<RouteDataObject> > excludeDuplications;
|
||||
SHARED_PTR<RouteSegment> original;
|
||||
for(int j = 0; j<subregions.size(); j++) {
|
||||
if(subregions[j]->isLoaded()) {
|
||||
SHARED_PTR<RouteSegment> segment = subregions[j]->routes[l];
|
||||
subregions[j]->access++;
|
||||
while (segment.get() != NULL) {
|
||||
SHARED_PTR<RouteDataObject> ro = segment->road;
|
||||
SHARED_PTR<RouteDataObject> toCmp = excludeDuplications[calcRouteId(ro, segment->getSegmentStart())];
|
||||
if (toCmp.get() == NULL || toCmp->pointsX.size() < ro->pointsX.size()) {
|
||||
excludeDuplications[calcRouteId(ro, segment->getSegmentStart())] = ro;
|
||||
SHARED_PTR<RouteSegment> s = SHARED_PTR<RouteSegment>(new RouteSegment(ro, segment->getSegmentStart()));
|
||||
s->next = original;
|
||||
original = s;
|
||||
}
|
||||
segment = segment->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
|
||||
bool isInterrupted(){
|
||||
return false;
|
||||
}
|
||||
float getHeuristicCoefficient(){
|
||||
return config.heurCoefficient;
|
||||
}
|
||||
|
||||
bool planRouteIn2Directions() {
|
||||
return getPlanRoadDirection() == 0;
|
||||
}
|
||||
int getPlanRoadDirection() {
|
||||
return config.planRoadDirection;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
vector<RouteSegmentResult> searchRouteInternal(RoutingContext* ctx, bool leftSideNavigation);
|
||||
#endif /*_OSMAND_BINARY_ROUTE_PLANNER_H*/
|
|
@ -1,313 +0,0 @@
|
|||
#include "common.h"
|
||||
|
||||
#include <SkPath.h>
|
||||
#include <SkBitmap.h>
|
||||
#include <SkImageDecoder.h>
|
||||
#include "osmand_log.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
# include <mmsystem.h>
|
||||
#elif defined(__APPLE__)
|
||||
# include <mach/mach_time.h>|
|
||||
#else
|
||||
# include <time.h>
|
||||
#endif
|
||||
|
||||
|
||||
TextDrawInfo::TextDrawInfo(std::string itext)
|
||||
: text(itext)
|
||||
, drawOnPath(false)
|
||||
, path(NULL)
|
||||
, pathRotate(0)
|
||||
{
|
||||
}
|
||||
|
||||
TextDrawInfo::~TextDrawInfo()
|
||||
{
|
||||
if (path)
|
||||
delete path;
|
||||
}
|
||||
|
||||
IconDrawInfo::IconDrawInfo()
|
||||
: bmp(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
RenderingContext::~RenderingContext()
|
||||
{
|
||||
std::vector<TextDrawInfo*>::iterator itTextToDraw;
|
||||
for(itTextToDraw = textToDraw.begin(); itTextToDraw != textToDraw.end(); ++itTextToDraw)
|
||||
delete (*itTextToDraw);
|
||||
}
|
||||
|
||||
bool RenderingContext::interrupted()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ElapsedTimer::ElapsedTimer()
|
||||
: elapsedTime(0)
|
||||
, enableFlag(true)
|
||||
, run(false)
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
mach_timebase_info(&machTimeInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ElapsedTimer::enable()
|
||||
{
|
||||
enableFlag = true;
|
||||
}
|
||||
|
||||
void ElapsedTimer::disable()
|
||||
{
|
||||
pause();
|
||||
enableFlag = false;
|
||||
}
|
||||
|
||||
void ElapsedTimer::start()
|
||||
{
|
||||
if (!enableFlag)
|
||||
return;
|
||||
if (!run)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
startInit = timeGetTime();
|
||||
#elif defined(__APPLE__)
|
||||
startInit = mach_absolute_time();
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, &startInit);
|
||||
#endif
|
||||
}
|
||||
run = true;
|
||||
}
|
||||
|
||||
void ElapsedTimer::pause()
|
||||
{
|
||||
if (!run)
|
||||
return;
|
||||
#if defined(_WIN32)
|
||||
endInit = timeGetTime();
|
||||
elapsedTime += (endInit - startInit) * 1000;
|
||||
#elif defined(__APPLE__)
|
||||
endInit = mach_absolute_time();
|
||||
uint64_t duration = endInit - startInit;
|
||||
duration *= machTimeInfo.numer;
|
||||
duration /= machTimeInfo.denom;
|
||||
elapsedTime += duration;
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, &endInit);
|
||||
int sec = endInit.tv_sec - startInit.tv_sec;
|
||||
if (sec > 0)
|
||||
elapsedTime += 1000000 * sec;
|
||||
elapsedTime += (endInit.tv_nsec - startInit.tv_nsec) / 1000;
|
||||
#endif
|
||||
run = false;
|
||||
}
|
||||
|
||||
int ElapsedTimer::getElapsedTime()
|
||||
{
|
||||
pause();
|
||||
return elapsedTime / 1000;
|
||||
}
|
||||
|
||||
SkBitmap* RenderingContext::getCachedBitmap(const std::string& bitmapResource) {
|
||||
if (defaultIconsDir.size() > 0) {
|
||||
string fl = string(defaultIconsDir + "h_" + bitmapResource + ".png");
|
||||
FILE* f = fopen(fl.c_str(), "r");
|
||||
if (f == NULL) {
|
||||
fl = string(defaultIconsDir + "g_" + bitmapResource + ".png");
|
||||
f = fopen(fl.c_str(), "r");
|
||||
}
|
||||
if (f != NULL) {
|
||||
fclose(f);
|
||||
osmand_log_print(LOG_INFO, "Open file %s", fl.c_str());
|
||||
SkBitmap* bmp = new SkBitmap();
|
||||
if (!SkImageDecoder::DecodeFile(fl.c_str(), bmp)) {
|
||||
return NULL;
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
UNORDERED(map)<std::string, SkBitmap*> cachedBitmaps;
|
||||
SkBitmap* getCachedBitmap(RenderingContext* rc, const std::string& bitmapResource)
|
||||
{
|
||||
|
||||
if(bitmapResource.size() == 0)
|
||||
return NULL;
|
||||
|
||||
// Try to find previously cached
|
||||
UNORDERED(map)<std::string, SkBitmap*>::iterator itPreviouslyCachedBitmap = cachedBitmaps.find(bitmapResource);
|
||||
if (itPreviouslyCachedBitmap != cachedBitmaps.end())
|
||||
return itPreviouslyCachedBitmap->second;
|
||||
|
||||
rc->nativeOperations.pause();
|
||||
SkBitmap* iconBitmap = rc->getCachedBitmap(bitmapResource);
|
||||
cachedBitmaps[bitmapResource] = iconBitmap;
|
||||
rc->nativeOperations.start();
|
||||
|
||||
return iconBitmap;
|
||||
}
|
||||
|
||||
void purgeCachedBitmaps() {
|
||||
UNORDERED(map)<std::string, SkBitmap*>::iterator it = cachedBitmaps.begin();
|
||||
for (; it != cachedBitmaps.end(); it++) {
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
|
||||
std::string RenderingContext::getTranslatedString(const std::string& src) {
|
||||
return src;
|
||||
}
|
||||
|
||||
std::string RenderingContext::getReshapedString(const std::string& src) {
|
||||
return src;
|
||||
}
|
||||
|
||||
|
||||
double getPowZoom(float zoom){
|
||||
if(zoom >= 0 && zoom - floor(zoom) < 0.05f){
|
||||
return 1 << ((int)zoom);
|
||||
} else {
|
||||
return pow(2, zoom);
|
||||
}
|
||||
}
|
||||
|
||||
double convert31YToMeters(int y1, int y2) {
|
||||
// translate into meters
|
||||
return (y1 - y2) * 0.01863f;
|
||||
}
|
||||
|
||||
double convert31XToMeters(int x1, int x2) {
|
||||
// translate into meters
|
||||
return (x1 - x2) * 0.011f;
|
||||
}
|
||||
|
||||
|
||||
double calculateProjection31TileMetric(int xA, int yA, int xB, int yB, int xC, int yC) {
|
||||
// Scalar multiplication between (AB, AC)
|
||||
double multiple = convert31XToMeters(xB, xA) * convert31XToMeters(xC, xA) + convert31YToMeters(yB, yA) * convert31YToMeters(yC, yA);
|
||||
return multiple;
|
||||
}
|
||||
double squareDist31TileMetric(int x1, int y1, int x2, int y2) {
|
||||
// translate into meters
|
||||
double dy = convert31YToMeters(y1, y2);
|
||||
double dx = convert31XToMeters(x1, x2);
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
|
||||
double checkLongitude(double longitude) {
|
||||
while (longitude < -180 || longitude > 180) {
|
||||
if (longitude < 0) {
|
||||
longitude += 360;
|
||||
} else {
|
||||
longitude -= 360;
|
||||
}
|
||||
}
|
||||
return longitude;
|
||||
}
|
||||
|
||||
double checkLatitude(double latitude) {
|
||||
while (latitude < -90 || latitude > 90) {
|
||||
if (latitude < 0) {
|
||||
latitude += 180;
|
||||
} else {
|
||||
latitude -= 180;
|
||||
}
|
||||
}
|
||||
if (latitude < -85.0511) {
|
||||
return -85.0511;
|
||||
} else if (latitude > 85.0511) {
|
||||
return 85.0511;
|
||||
}
|
||||
return latitude;
|
||||
}
|
||||
|
||||
|
||||
int get31TileNumberX(double longitude){
|
||||
longitude = checkLongitude(longitude);
|
||||
long long int l = 1;
|
||||
l <<= 31;
|
||||
return (int)((longitude + 180)/360 * l);
|
||||
}
|
||||
|
||||
int get31TileNumberY(double latitude) {
|
||||
latitude = checkLatitude(latitude);
|
||||
double eval = log(tan(toRadians(latitude)) + 1 / cos(toRadians(latitude)));
|
||||
long long int l = 1;
|
||||
l <<= 31;
|
||||
if (eval > M_PI) {
|
||||
eval = M_PI;
|
||||
}
|
||||
return (int) ((1 - eval / M_PI) / 2 * l);
|
||||
}
|
||||
|
||||
double getLongitudeFromTile(float zoom, double x) {
|
||||
return x / getPowZoom(zoom) * 360.0 - 180.0;
|
||||
}
|
||||
|
||||
|
||||
double getLatitudeFromTile(float zoom, double y){
|
||||
int sign = y < 0 ? -1 : 1;
|
||||
double result = atan(sign*sinh(M_PI * (1 - 2 * y / getPowZoom(zoom)))) * 180. / M_PI;
|
||||
return result;
|
||||
}
|
||||
|
||||
double get31LongitudeX(int tileX){
|
||||
return getLongitudeFromTile(21, tileX /1024.);
|
||||
}
|
||||
|
||||
double get31LatitudeY(int tileY){
|
||||
return getLatitudeFromTile(21, tileY /1024.);
|
||||
|
||||
}
|
||||
|
||||
|
||||
double getTileNumberX(float zoom, double longitude) {
|
||||
if (longitude == 180.) {
|
||||
return getPowZoom(zoom) - 1;
|
||||
}
|
||||
longitude = checkLongitude(longitude);
|
||||
return (longitude + 180.) / 360. * getPowZoom(zoom);
|
||||
}
|
||||
|
||||
|
||||
double getTileNumberY(float zoom, double latitude) {
|
||||
latitude = checkLatitude(latitude);
|
||||
double eval = log(tan(toRadians(latitude)) + 1 / cos(toRadians(latitude)));
|
||||
if (isinf(eval) || isnan(eval)) {
|
||||
latitude = latitude < 0 ? -89.9 : 89.9;
|
||||
eval = log(tan(toRadians(latitude)) + 1 / cos(toRadians(latitude)));
|
||||
}
|
||||
double result = (1 - eval / M_PI) / 2 * getPowZoom(zoom);
|
||||
return result;
|
||||
}
|
||||
|
||||
double getDistance(double lat1, double lon1, double lat2, double lon2) {
|
||||
double R = 6371; // km
|
||||
double dLat = toRadians(lat2 - lat1);
|
||||
double dLon = toRadians(lon2 - lon1);
|
||||
double a = sin(dLat / 2) * sin(dLat / 2)
|
||||
+ cos(toRadians(lat1)) * cos(toRadians(lat2)) * sin(dLon / 2) * sin(dLon / 2);
|
||||
double c = 2 * atan2(sqrt(a), sqrt(1 - a));
|
||||
return R * c * 1000;
|
||||
}
|
||||
|
||||
double alignAngleDifference(double diff) {
|
||||
while (diff > M_PI) {
|
||||
diff -= 2 * M_PI;
|
||||
}
|
||||
while (diff <= -M_PI) {
|
||||
diff += 2 * M_PI;
|
||||
}
|
||||
return diff;
|
||||
|
||||
}
|
|
@ -1,338 +0,0 @@
|
|||
#ifndef _OSMAND_COMMON_H
|
||||
#define _OSMAND_COMMON_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#if defined(ANDROID)
|
||||
# include <unordered_map>
|
||||
# include <unordered_set>
|
||||
#elif defined(__APPLE__)
|
||||
# include <tr1/unordered_map>
|
||||
# include <tr1/unordered_set>
|
||||
#else
|
||||
# include <unordered_map>
|
||||
# include <unordered_set>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <mach/mach_time.h>|
|
||||
#endif
|
||||
|
||||
#include <SkPath.h>
|
||||
#include <SkBitmap.h>
|
||||
|
||||
#include "osmand_log.h"
|
||||
|
||||
// M_PI is no longer part of math.h/cmath by standart, but some GCC's define them
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#if !defined(M_PI)
|
||||
const double M_PI = 3.14159265358979323846;
|
||||
#endif
|
||||
#if !defined(M_PI_2)
|
||||
const double M_PI_2 = M_PI / 2.0;
|
||||
#endif
|
||||
|
||||
// Wrapper for unordered classes
|
||||
#if defined(ANDROID)
|
||||
# define UNORDERED_NAMESPACE std::tr1
|
||||
# define UNORDERED_map unordered_map
|
||||
# define UNORDERED_set unordered_set
|
||||
#elif defined(__APPLE__)
|
||||
# define UNORDERED_NAMESPACE std::tr1
|
||||
# define UNORDERED_map unordered_map
|
||||
# define UNORDERED_set unordered_set
|
||||
#else
|
||||
# define UNORDERED_NAMESPACE std
|
||||
# define UNORDERED_map unordered_map
|
||||
# define UNORDERED_set unordered_set
|
||||
//# define UNORDERED_map map
|
||||
//# define UNORDERED_set set
|
||||
#endif
|
||||
#define UNORDERED(cls) UNORDERED_NAMESPACE::UNORDERED_##cls
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include "shared_ptr.h"
|
||||
#define SHARED_PTR my_shared_ptr
|
||||
//# include <tr1/shared_ptr.h>
|
||||
//# define SHARED_PTR std::tr1::shared_ptr
|
||||
#elif defined(WINDOWS)
|
||||
#else
|
||||
//# include "shared_ptr.h"
|
||||
//# define SHARED_PTR my_shared_ptr
|
||||
# include <tr1/memory>
|
||||
# define SHARED_PTR std::tr1::shared_ptr
|
||||
#endif
|
||||
|
||||
|
||||
// Better don't do this
|
||||
using namespace std;
|
||||
|
||||
#ifdef PROFILE_NATIVE_OPERATIONS
|
||||
#define PROFILE_NATIVE_OPERATION(rc, op) rc->nativeOperations.pause(); op; rc->nativeOperations.start()
|
||||
#else
|
||||
#define PROFILE_NATIVE_OPERATION(rc, op) op;
|
||||
#endif
|
||||
|
||||
struct RenderingContext;
|
||||
|
||||
inline double toRadians(double angdeg) {
|
||||
return angdeg / 180 * M_PI;
|
||||
}
|
||||
|
||||
class ElapsedTimer
|
||||
{
|
||||
private:
|
||||
long elapsedTime;
|
||||
bool enableFlag;
|
||||
bool run;
|
||||
|
||||
#if defined(_WIN32)
|
||||
DWORD startInit;
|
||||
DWORD endInit;
|
||||
#elif defined(__APPLE__)
|
||||
mach_timebase_info_data_t machTimeInfo;
|
||||
uint64_t startInit;
|
||||
uint64_t endInit;
|
||||
#else
|
||||
timespec startInit;
|
||||
timespec endInit;
|
||||
#endif
|
||||
|
||||
public:
|
||||
ElapsedTimer();
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
void start();
|
||||
void pause();
|
||||
|
||||
int getElapsedTime();
|
||||
};
|
||||
|
||||
struct TextDrawInfo {
|
||||
TextDrawInfo(std::string);
|
||||
~TextDrawInfo();
|
||||
|
||||
std::string text;
|
||||
|
||||
SkRect bounds;
|
||||
float centerX;
|
||||
float centerY;
|
||||
|
||||
float textSize;
|
||||
float minDistance;
|
||||
int textColor;
|
||||
int textShadow;
|
||||
uint32_t textWrap;
|
||||
bool bold;
|
||||
std::string shieldRes;
|
||||
int textOrder;
|
||||
|
||||
bool drawOnPath;
|
||||
SkPath* path;
|
||||
float pathRotate;
|
||||
float vOffset;
|
||||
float hOffset;
|
||||
};
|
||||
|
||||
struct IconDrawInfo
|
||||
{
|
||||
IconDrawInfo();
|
||||
|
||||
SkBitmap* bmp;
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
static const int TILE_SIZE = 256;
|
||||
struct RenderingContext
|
||||
{
|
||||
private :
|
||||
// parameters
|
||||
bool useEnglishNames;
|
||||
float density;
|
||||
|
||||
float leftX;
|
||||
float topY;
|
||||
int width;
|
||||
int height;
|
||||
int defaultColor;
|
||||
|
||||
int zoom;
|
||||
float rotate;
|
||||
// int shadowRenderingMode = 0; // no shadow (minumum CPU)
|
||||
// int shadowRenderingMode = 1; // classic shadow (the implementaton in master)
|
||||
// int shadowRenderingMode = 2; // blur shadow (most CPU, but still reasonable)
|
||||
// int shadowRenderingMode = 3; solid border (CPU use like classic version or even smaller)
|
||||
int shadowRenderingMode;
|
||||
int shadowRenderingColor;
|
||||
string defaultIconsDir;
|
||||
|
||||
public:
|
||||
// debug purpose
|
||||
int pointCount;
|
||||
int pointInsideCount;
|
||||
int visible;
|
||||
int allObjects;
|
||||
int lastRenderedKey;
|
||||
ElapsedTimer textRendering;
|
||||
ElapsedTimer nativeOperations;
|
||||
|
||||
// because they used in 3rd party functions
|
||||
public :
|
||||
|
||||
// calculated
|
||||
float tileDivisor;
|
||||
float cosRotateTileSize;
|
||||
float sinRotateTileSize;
|
||||
|
||||
std::vector<TextDrawInfo*> textToDraw;
|
||||
std::vector<IconDrawInfo> iconsToDraw;
|
||||
// use to calculate points
|
||||
float calcX;
|
||||
float calcY;
|
||||
|
||||
// not expect any shadow
|
||||
int shadowLevelMin;
|
||||
int shadowLevelMax;
|
||||
int polygonMinSizeToDisplay;
|
||||
int roadDensityZoomTile;
|
||||
int roadsDensityLimitPerTile;
|
||||
|
||||
public:
|
||||
RenderingContext() : shadowLevelMax(0), shadowLevelMin(256), density(true), useEnglishNames(false), pointCount(0),
|
||||
pointInsideCount(0), visible(0), allObjects(0), shadowRenderingColor(0xff969696) {
|
||||
setRotate(0);
|
||||
setZoom(15);
|
||||
setDefaultColor(0xfff1eee8);
|
||||
roadsDensityLimitPerTile = 0;
|
||||
roadDensityZoomTile = 0;
|
||||
polygonMinSizeToDisplay = 0;
|
||||
}
|
||||
virtual ~RenderingContext();
|
||||
|
||||
virtual bool interrupted();
|
||||
virtual SkBitmap* getCachedBitmap(const std::string& bitmapResource);
|
||||
virtual std::string getTranslatedString(const std::string& src);
|
||||
virtual std::string getReshapedString(const std::string& src);
|
||||
|
||||
void setDefaultIconsDir(string path) {
|
||||
defaultIconsDir = path;
|
||||
}
|
||||
|
||||
void setZoom(int z) {
|
||||
this->zoom = z;
|
||||
this->tileDivisor = (1 << (31 - z));
|
||||
}
|
||||
|
||||
void setTileDivisor(float tileDivisor) {
|
||||
this->tileDivisor = tileDivisor;
|
||||
}
|
||||
|
||||
void setDefaultColor(int z) {
|
||||
this->defaultColor = z;
|
||||
}
|
||||
|
||||
void setRotate(float rot) {
|
||||
this->rotate = rot;
|
||||
this->cosRotateTileSize = cos(toRadians(rot)) * TILE_SIZE;
|
||||
this->sinRotateTileSize = sin(toRadians(rot)) * TILE_SIZE;
|
||||
}
|
||||
|
||||
void setLocation(double leftX, double topY) {
|
||||
this->leftX = leftX;
|
||||
this->topY = topY;
|
||||
}
|
||||
|
||||
void setDimension(int width, int height) {
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
}
|
||||
|
||||
inline int getShadowRenderingMode(){
|
||||
return shadowRenderingMode;
|
||||
}
|
||||
|
||||
int getShadowRenderingColor(){
|
||||
return shadowRenderingColor;
|
||||
}
|
||||
|
||||
void setShadowRenderingColor(int color) {
|
||||
shadowRenderingColor = color;
|
||||
}
|
||||
|
||||
inline int getWidth(){
|
||||
return width;
|
||||
}
|
||||
|
||||
inline int getDefaultColor(){
|
||||
return defaultColor;
|
||||
}
|
||||
|
||||
inline int getHeight(){
|
||||
return height;
|
||||
}
|
||||
|
||||
inline int getZoom() {
|
||||
return zoom;
|
||||
}
|
||||
|
||||
inline float getLeft() {
|
||||
return leftX;
|
||||
}
|
||||
|
||||
inline float getTop() {
|
||||
return topY;
|
||||
}
|
||||
|
||||
void setShadowRenderingMode(int mode){
|
||||
this->shadowRenderingMode = mode;
|
||||
}
|
||||
|
||||
void setDensityScale(float val) {
|
||||
density = val;
|
||||
}
|
||||
|
||||
float getDensityValue(float val) {
|
||||
return val * density;
|
||||
}
|
||||
|
||||
void setUseEnglishNames(bool b){
|
||||
this->useEnglishNames = b;
|
||||
}
|
||||
|
||||
bool isUsingEnglishNames(){
|
||||
return this->useEnglishNames;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
SkBitmap* getCachedBitmap(RenderingContext* rc, const std::string& bitmapResource);
|
||||
void purgeCachedBitmaps();
|
||||
|
||||
int get31TileNumberX(double longitude);
|
||||
int get31TileNumberY( double latitude);
|
||||
|
||||
double getPowZoom(float zoom);
|
||||
|
||||
double getLongitudeFromTile(float zoom, double x) ;
|
||||
double getLatitudeFromTile(float zoom, double y);
|
||||
|
||||
double get31LongitudeX(int tileX);
|
||||
double get31LatitudeY(int tileY);
|
||||
double getTileNumberX(float zoom, double longitude);
|
||||
double getTileNumberY(float zoom, double latitude);
|
||||
double getDistance(double lat1, double lon1, double lat2, double lon2);
|
||||
double getPowZoom(float zoom);
|
||||
|
||||
double calculateProjection31TileMetric(int xA, int yA, int xB, int yB, int xC, int yC);
|
||||
double squareDist31TileMetric(int x1, int y1, int x2, int y2) ;
|
||||
double convert31YToMeters(int y1, int y2);
|
||||
double convert31XToMeters(int y1, int y2);
|
||||
double alignAngleDifference(double diff);
|
||||
|
||||
|
||||
#endif /*_OSMAND_COMMON_H*/
|
|
@ -1,5 +0,0 @@
|
|||
#ifndef _JAVA_COMMON_WRAP_CPP
|
||||
#define _JAVA_COMMON_WRAP_CPP
|
||||
|
||||
|
||||
#endif
|
|
@ -1,313 +0,0 @@
|
|||
#ifndef _JAVA_RENDER_RULES_H
|
||||
#define _JAVA_RENDER_RULES_H
|
||||
|
||||
#include <jni.h>
|
||||
#include "java_wrap.h"
|
||||
#include "common.h"
|
||||
#include "renderRules.h"
|
||||
|
||||
|
||||
jclass ListClass;
|
||||
jmethodID List_size;
|
||||
jmethodID List_get;
|
||||
|
||||
jclass RenderingRuleClass;
|
||||
jfieldID RenderingRule_properties;
|
||||
jfieldID RenderingRule_intProperties;
|
||||
jfieldID RenderingRule_floatProperties;
|
||||
jfieldID RenderingRule_ifElseChildren;
|
||||
jfieldID RenderingRule_ifChildren;
|
||||
|
||||
jclass RenderingRuleStoragePropertiesClass;
|
||||
jfieldID RenderingRuleStorageProperties_rules;
|
||||
|
||||
jclass RenderingRulePropertyClass;
|
||||
jfieldID RenderingRuleProperty_type;
|
||||
jfieldID RenderingRuleProperty_input;
|
||||
jfieldID RenderingRuleProperty_attrName;
|
||||
|
||||
jclass RenderingRulesStorageClass;
|
||||
jfieldID RenderingRulesStorageClass_dictionary;
|
||||
jfieldID RenderingRulesStorage_PROPS;
|
||||
jmethodID RenderingRulesStorage_getRules;
|
||||
jmethodID RenderingRulesStorage_getRenderingAttributeNames;
|
||||
jmethodID RenderingRulesStorage_getRenderingAttributeValues;
|
||||
|
||||
jclass RenderingRuleSearchRequestClass;
|
||||
jfieldID RenderingRuleSearchRequest_storage;
|
||||
jfieldID RenderingRuleSearchRequest_props;
|
||||
jfieldID RenderingRuleSearchRequest_values;
|
||||
jfieldID RenderingRuleSearchRequest_fvalues;
|
||||
jfieldID RenderingRuleSearchRequest_savedValues;
|
||||
jfieldID RenderingRuleSearchRequest_savedFvalues;
|
||||
|
||||
RenderingRule* createRenderingRule(JNIEnv* env, jobject rRule, RenderingRulesStorage* st) {
|
||||
map<string,string> empty;
|
||||
RenderingRule* rule = new RenderingRule(empty,st);
|
||||
jobjectArray props = (jobjectArray) env->GetObjectField(rRule, RenderingRule_properties);
|
||||
jintArray intProps = (jintArray) env->GetObjectField(rRule, RenderingRule_intProperties);
|
||||
jfloatArray floatProps = (jfloatArray) env->GetObjectField(rRule, RenderingRule_floatProperties);
|
||||
jobject ifChildren = env->GetObjectField(rRule, RenderingRule_ifChildren);
|
||||
jobject ifElseChildren = env->GetObjectField(rRule, RenderingRule_ifElseChildren);
|
||||
|
||||
jsize sz = env->GetArrayLength(props);
|
||||
|
||||
if (floatProps != NULL) {
|
||||
jfloat* fe = env->GetFloatArrayElements(floatProps, NULL);
|
||||
for (int j = 0; j < sz; j++) {
|
||||
rule->floatProperties.push_back(fe[j]);
|
||||
}
|
||||
env->ReleaseFloatArrayElements(floatProps, fe, JNI_ABORT);
|
||||
env->DeleteLocalRef(floatProps);
|
||||
} else {
|
||||
rule->floatProperties.assign(sz, 0);
|
||||
}
|
||||
|
||||
if (intProps != NULL) {
|
||||
jint* ie = env->GetIntArrayElements(intProps, NULL);
|
||||
for (int j = 0; j < sz; j++) {
|
||||
rule->intProperties.push_back(ie[j]);
|
||||
}
|
||||
env->ReleaseIntArrayElements(intProps, ie, JNI_ABORT);
|
||||
env->DeleteLocalRef(intProps);
|
||||
} else {
|
||||
rule->intProperties.assign(sz, -1);
|
||||
}
|
||||
|
||||
for (jsize i = 0; i < sz; i++) {
|
||||
jobject prop = env->GetObjectArrayElement(props, i);
|
||||
std::string attr = getStringField(env, prop, RenderingRuleProperty_attrName);
|
||||
RenderingRuleProperty* p = st->PROPS.getProperty(attr);
|
||||
rule->properties.push_back(p);
|
||||
env->DeleteLocalRef(prop);
|
||||
}
|
||||
env->DeleteLocalRef(props);
|
||||
|
||||
if (ifChildren != NULL) {
|
||||
sz = env->CallIntMethod(ifChildren, List_size);
|
||||
for (jsize i = 0; i < sz; i++) {
|
||||
jobject o = env->CallObjectMethod(ifChildren, List_get, i);
|
||||
rule->ifChildren.push_back(createRenderingRule(env, o, st));
|
||||
env->DeleteLocalRef(o);
|
||||
}
|
||||
env->DeleteLocalRef(ifChildren);
|
||||
}
|
||||
|
||||
if (ifElseChildren != NULL) {
|
||||
sz = env->CallIntMethod(ifElseChildren, List_size);
|
||||
for (jsize i = 0; i < sz; i++) {
|
||||
jobject o = env->CallObjectMethod(ifElseChildren, List_get, i);
|
||||
rule->ifElseChildren.push_back(createRenderingRule(env, o, st));
|
||||
env->DeleteLocalRef(o);
|
||||
}
|
||||
env->DeleteLocalRef(ifElseChildren);
|
||||
}
|
||||
|
||||
return rule;
|
||||
}
|
||||
|
||||
|
||||
void initDictionary(JNIEnv* env, RenderingRulesStorage* storage, jobject javaStorage) {
|
||||
jobject listDictionary = env->GetObjectField(javaStorage, RenderingRulesStorageClass_dictionary);
|
||||
uint32_t sz = env->CallIntMethod(listDictionary, List_size);
|
||||
uint32_t i = 0;
|
||||
for (; i < sz; i++) {
|
||||
jstring st = (jstring) env->CallObjectMethod(listDictionary, List_get, i);
|
||||
const char* utf = env->GetStringUTFChars(st, NULL);
|
||||
std::string d = std::string(utf);
|
||||
|
||||
env->ReleaseStringUTFChars(st, utf);
|
||||
env->DeleteLocalRef(st);
|
||||
storage->registerString(d);
|
||||
}
|
||||
env->DeleteLocalRef(listDictionary);
|
||||
}
|
||||
|
||||
void initAttributes(JNIEnv* env, RenderingRulesStorage* st, jobject javaStorage) {
|
||||
jobjectArray attributeNames = (jobjectArray) env->CallObjectMethod(javaStorage, RenderingRulesStorage_getRenderingAttributeNames);
|
||||
jobjectArray attributeValues = (jobjectArray) env->CallObjectMethod(javaStorage, RenderingRulesStorage_getRenderingAttributeValues);
|
||||
uint32_t sz = env->GetArrayLength(attributeNames);
|
||||
for (uint32_t i = 0; i < sz; i++) {
|
||||
jstring nm = (jstring) env->GetObjectArrayElement(attributeNames, i);
|
||||
jobject vl = env->GetObjectArrayElement(attributeValues, i);
|
||||
RenderingRule* rule = createRenderingRule(env, vl, st);
|
||||
st->renderingAttributes[getString(env, nm)] = rule;
|
||||
env->DeleteLocalRef(nm);
|
||||
env->DeleteLocalRef(vl);
|
||||
}
|
||||
env->DeleteLocalRef(attributeNames);
|
||||
env->DeleteLocalRef(attributeValues);
|
||||
|
||||
}
|
||||
|
||||
void initProperties(JNIEnv* env, RenderingRulesStorage* st, jobject javaStorage) {
|
||||
jobject props = env->GetObjectField(javaStorage, RenderingRulesStorage_PROPS);
|
||||
jobject listProps = env->GetObjectField(props, RenderingRuleStorageProperties_rules);
|
||||
uint32_t sz = env->CallIntMethod(listProps, List_size);
|
||||
uint32_t i = 0;
|
||||
for (; i < sz; i++) {
|
||||
jobject rulePrope = env->CallObjectMethod(listProps, List_get, i);
|
||||
bool input = (env->GetBooleanField(rulePrope, RenderingRuleProperty_input) == JNI_TRUE);
|
||||
int type = env->GetIntField(rulePrope, RenderingRuleProperty_type);
|
||||
std::string name = getStringField(env, rulePrope, RenderingRuleProperty_attrName);
|
||||
RenderingRuleProperty* prop = new RenderingRuleProperty(name, type, input, i);
|
||||
st->PROPS.registerRuleInternal(prop);
|
||||
env->DeleteLocalRef(rulePrope);
|
||||
}
|
||||
st->PROPS.createDefaultProperties();
|
||||
env->DeleteLocalRef(props);
|
||||
env->DeleteLocalRef(listProps);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void initRules(JNIEnv* env, RenderingRulesStorage* st, jobject javaStorage) {
|
||||
for (int i = 1; i < RenderingRulesStorage::SIZE_STATES; i++) {
|
||||
jobjectArray rules = (jobjectArray) env->CallObjectMethod(javaStorage, RenderingRulesStorage_getRules, i);
|
||||
jsize len = env->GetArrayLength(rules);
|
||||
for (jsize j = 0; j < len; j++) {
|
||||
jobject rRule = env->GetObjectArrayElement(rules, j);
|
||||
RenderingRule* rule = createRenderingRule(env, rRule, st);
|
||||
env->DeleteLocalRef(rRule);
|
||||
st->registerGlobalRule(rule, i);
|
||||
}
|
||||
env->DeleteLocalRef(rules);
|
||||
}
|
||||
}
|
||||
|
||||
RenderingRulesStorage* createRenderingRulesStorage(JNIEnv* env, jobject storage) {
|
||||
RenderingRulesStorage* res = new RenderingRulesStorage(storage, false);
|
||||
initDictionary(env, res, storage);
|
||||
initProperties(env, res, storage);
|
||||
initRules(env, res, storage);
|
||||
initAttributes(env, res, storage);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void initRenderingRuleSearchRequest(JNIEnv* env, RenderingRuleSearchRequest* r, jobject rrs) {
|
||||
jsize sz;
|
||||
jobjectArray oa = (jobjectArray) env->GetObjectField(rrs, RenderingRuleSearchRequest_props);
|
||||
sz = env->GetArrayLength(oa);
|
||||
std::vector<RenderingRuleProperty*> requestProps;
|
||||
vector<int> values;
|
||||
vector<float> fvalues;
|
||||
vector<int> savedValues;
|
||||
vector<float> savedFvalues;
|
||||
|
||||
for (jsize i = 0; i < sz; i++) {
|
||||
jobject prop = env->GetObjectArrayElement(oa, i);
|
||||
std::string attr = getStringField(env, prop, RenderingRuleProperty_attrName);
|
||||
RenderingRuleProperty* p = r->storage->PROPS.getProperty(attr);
|
||||
requestProps.push_back(p);
|
||||
env->DeleteLocalRef(prop);
|
||||
}
|
||||
env->DeleteLocalRef(oa);
|
||||
sz = r->storage->PROPS.properties.size();
|
||||
{
|
||||
values.resize(sz , 0);
|
||||
jintArray ia = (jintArray) env->GetObjectField(rrs, RenderingRuleSearchRequest_values);
|
||||
jint* ie = env->GetIntArrayElements(ia, NULL);
|
||||
for (int i = 0; i < sz; i++) {
|
||||
values[requestProps.at(i)->id] = ie[i];
|
||||
}
|
||||
env->ReleaseIntArrayElements(ia, ie, JNI_ABORT);
|
||||
env->DeleteLocalRef(ia);
|
||||
}
|
||||
|
||||
{
|
||||
fvalues .resize(sz , 0);
|
||||
jfloatArray ia = (jfloatArray) env->GetObjectField(rrs, RenderingRuleSearchRequest_fvalues);
|
||||
jfloat* ie = env->GetFloatArrayElements(ia, NULL);
|
||||
for (int i = 0; i < sz; i++) {
|
||||
fvalues[requestProps.at(i)->id] = ie[i];
|
||||
}
|
||||
env->ReleaseFloatArrayElements(ia, ie, JNI_ABORT);
|
||||
env->DeleteLocalRef(ia);
|
||||
}
|
||||
|
||||
{
|
||||
savedValues.resize(sz , 0);
|
||||
jintArray ia = (jintArray) env->GetObjectField(rrs, RenderingRuleSearchRequest_values);
|
||||
jint* ie = env->GetIntArrayElements(ia, NULL);
|
||||
for (int i = 0; i < sz; i++) {
|
||||
savedValues[requestProps.at(i)->id] = ie[i];
|
||||
}
|
||||
env->ReleaseIntArrayElements(ia, ie, JNI_ABORT);
|
||||
env->DeleteLocalRef(ia);
|
||||
}
|
||||
|
||||
{
|
||||
savedFvalues .resize(sz , 0);
|
||||
jfloatArray ia = (jfloatArray) env->GetObjectField(rrs, RenderingRuleSearchRequest_fvalues);
|
||||
jfloat* ie = env->GetFloatArrayElements(ia, NULL);
|
||||
for (int i = 0; i < sz; i++) {
|
||||
savedFvalues[requestProps.at(i)->id] = ie[i];
|
||||
}
|
||||
env->ReleaseFloatArrayElements(ia, ie, JNI_ABORT);
|
||||
env->DeleteLocalRef(ia);
|
||||
}
|
||||
r->externalInitialize(values, fvalues, savedValues, savedFvalues);
|
||||
}
|
||||
|
||||
|
||||
void loadJniRenderingRules(JNIEnv* env) {
|
||||
RenderingRuleClass = findClass(env, "net/osmand/render/RenderingRule");
|
||||
RenderingRule_properties = env->GetFieldID(RenderingRuleClass, "properties",
|
||||
"[Lnet/osmand/render/RenderingRuleProperty;");
|
||||
RenderingRule_intProperties = env->GetFieldID(RenderingRuleClass, "intProperties", "[I");
|
||||
RenderingRule_floatProperties = env->GetFieldID(RenderingRuleClass, "floatProperties", "[F");
|
||||
RenderingRule_ifElseChildren = env->GetFieldID(RenderingRuleClass, "ifElseChildren", "Ljava/util/List;");
|
||||
RenderingRule_ifChildren = env->GetFieldID(RenderingRuleClass, "ifChildren", "Ljava/util/List;");
|
||||
|
||||
RenderingRuleStoragePropertiesClass = findClass(env, "net/osmand/render/RenderingRuleStorageProperties");
|
||||
RenderingRuleStorageProperties_rules = env->GetFieldID(RenderingRuleStoragePropertiesClass, "rules",
|
||||
"Ljava/util/List;");
|
||||
|
||||
RenderingRulePropertyClass = findClass(env, "net/osmand/render/RenderingRuleProperty");
|
||||
RenderingRuleProperty_type = env->GetFieldID(RenderingRulePropertyClass, "type", "I");
|
||||
RenderingRuleProperty_input = env->GetFieldID(RenderingRulePropertyClass, "input", "Z");
|
||||
RenderingRuleProperty_attrName = env->GetFieldID(RenderingRulePropertyClass, "attrName",
|
||||
"Ljava/lang/String;");
|
||||
|
||||
RenderingRulesStorageClass = findClass(env, "net/osmand/render/RenderingRulesStorage");
|
||||
RenderingRulesStorageClass_dictionary = env->GetFieldID(RenderingRulesStorageClass, "dictionary",
|
||||
"Ljava/util/List;");
|
||||
RenderingRulesStorage_PROPS = env->GetFieldID(RenderingRulesStorageClass, "PROPS",
|
||||
"Lnet/osmand/render/RenderingRuleStorageProperties;");
|
||||
RenderingRulesStorage_getRules = env->GetMethodID(RenderingRulesStorageClass, "getRules",
|
||||
"(I)[Lnet/osmand/render/RenderingRule;");
|
||||
RenderingRulesStorage_getRenderingAttributeNames = env->GetMethodID(RenderingRulesStorageClass, "getRenderingAttributeNames",
|
||||
"()[Ljava/lang/String;");
|
||||
RenderingRulesStorage_getRenderingAttributeValues = env->GetMethodID(RenderingRulesStorageClass, "getRenderingAttributeValues",
|
||||
"()[Lnet/osmand/render/RenderingRule;");
|
||||
|
||||
ListClass = findClass(env, "java/util/List");
|
||||
List_size = env->GetMethodID(ListClass, "size", "()I");
|
||||
List_get = env->GetMethodID(ListClass, "get", "(I)Ljava/lang/Object;");
|
||||
|
||||
RenderingRuleSearchRequestClass = findClass(env, "net/osmand/render/RenderingRuleSearchRequest");
|
||||
RenderingRuleSearchRequest_storage = env->GetFieldID(RenderingRuleSearchRequestClass, "storage",
|
||||
"Lnet/osmand/render/RenderingRulesStorage;");
|
||||
RenderingRuleSearchRequest_props = env->GetFieldID(RenderingRuleSearchRequestClass, "props",
|
||||
"[Lnet/osmand/render/RenderingRuleProperty;");
|
||||
RenderingRuleSearchRequest_values = env->GetFieldID(RenderingRuleSearchRequestClass, "values", "[I");
|
||||
RenderingRuleSearchRequest_fvalues = env->GetFieldID(RenderingRuleSearchRequestClass, "fvalues", "[F");
|
||||
RenderingRuleSearchRequest_savedValues = env->GetFieldID(RenderingRuleSearchRequestClass, "savedValues",
|
||||
"[I");
|
||||
RenderingRuleSearchRequest_savedFvalues = env->GetFieldID(RenderingRuleSearchRequestClass, "savedFvalues",
|
||||
"[F");
|
||||
|
||||
}
|
||||
|
||||
void unloadJniRenderRules(JNIEnv* env) {
|
||||
env->DeleteGlobalRef(RenderingRuleSearchRequestClass);
|
||||
env->DeleteGlobalRef(RenderingRuleClass);
|
||||
env->DeleteGlobalRef(RenderingRulePropertyClass);
|
||||
env->DeleteGlobalRef(RenderingRuleStoragePropertiesClass);
|
||||
env->DeleteGlobalRef(RenderingRulesStorageClass);
|
||||
env->DeleteGlobalRef(ListClass);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,874 +0,0 @@
|
|||
#ifdef ANDROID_BUILD
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#include <SkBitmap.h>
|
||||
#include <SkCanvas.h>
|
||||
#include <SkImageDecoder.h>
|
||||
#include <SkImageEncoder.h>
|
||||
#include <SkStream.h>
|
||||
#include "java_renderRules.h"
|
||||
#include "common.h"
|
||||
#include "java_wrap.h"
|
||||
#include "binaryRead.h"
|
||||
#include "rendering.h"
|
||||
#include "binaryRoutePlanner.h"
|
||||
|
||||
|
||||
JavaVM* globalJVM = NULL;
|
||||
void loadJniRenderingContext(JNIEnv* env);
|
||||
void loadJniRenderingRules(JNIEnv* env);
|
||||
jclass jclassIntArray ;
|
||||
jclass jclassString;
|
||||
jmethodID jmethod_Object_toString = NULL;
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
|
||||
{
|
||||
JNIEnv* globalJniEnv;
|
||||
if(vm->GetEnv((void **)&globalJniEnv, JNI_VERSION_1_6))
|
||||
return JNI_ERR; /* JNI version not supported */
|
||||
globalJVM = vm;
|
||||
loadJniRenderingContext(globalJniEnv);
|
||||
loadJniRenderingRules(globalJniEnv);
|
||||
jclassIntArray = findClass(globalJniEnv, "[I");
|
||||
jclassString = findClass(globalJniEnv, "java/lang/String");
|
||||
|
||||
osmand_log_print(LOG_INFO, "JNI_OnLoad completed");
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_net_osmand_NativeLibrary_deleteSearchResult(JNIEnv* ienv,
|
||||
jobject obj, jlong searchResult) {
|
||||
ResultPublisher* result = (ResultPublisher*) searchResult;
|
||||
if(result != NULL){
|
||||
delete result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_net_osmand_NativeLibrary_closeBinaryMapFile(JNIEnv* ienv,
|
||||
jobject obj, jobject path) {
|
||||
const char* utf = ienv->GetStringUTFChars((jstring) path, NULL);
|
||||
std::string inputName(utf);
|
||||
ienv->ReleaseStringUTFChars((jstring) path, utf);
|
||||
closeBinaryMapFile(inputName);
|
||||
}
|
||||
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL Java_net_osmand_NativeLibrary_initCacheMapFiles(JNIEnv* ienv,
|
||||
jobject obj,
|
||||
jobject path) {
|
||||
const char* utf = ienv->GetStringUTFChars((jstring) path, NULL);
|
||||
std::string inputName(utf);
|
||||
ienv->ReleaseStringUTFChars((jstring) path, utf);
|
||||
return initMapFilesFromCache(inputName);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL Java_net_osmand_NativeLibrary_initBinaryMapFile(JNIEnv* ienv,
|
||||
jobject obj, jobject path) {
|
||||
// Verify that the version of the library that we linked against is
|
||||
const char* utf = ienv->GetStringUTFChars((jstring) path, NULL);
|
||||
std::string inputName(utf);
|
||||
ienv->ReleaseStringUTFChars((jstring) path, utf);
|
||||
BinaryMapFile* fl = initBinaryMapFile(inputName);
|
||||
if(fl == NULL) {
|
||||
osmand_log_print(LOG_WARN, "File %s was not initialized", inputName.c_str());
|
||||
}
|
||||
return fl != NULL;
|
||||
}
|
||||
|
||||
|
||||
// Global object
|
||||
UNORDERED(map)<std::string, RenderingRulesStorage*> cachedStorages;
|
||||
|
||||
RenderingRulesStorage* getStorage(JNIEnv* env, jobject storage) {
|
||||
std::string hash = getStringMethod(env, storage, jmethod_Object_toString);
|
||||
if (cachedStorages.find(hash) == cachedStorages.end()) {
|
||||
osmand_log_print(LOG_DEBUG, "Init rendering storage %s ", hash.c_str());
|
||||
cachedStorages[hash] = createRenderingRulesStorage(env, storage);
|
||||
}
|
||||
return cachedStorages[hash];
|
||||
}
|
||||
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_net_osmand_NativeLibrary_initRenderingRulesStorage(JNIEnv* ienv,
|
||||
jobject obj, jobject storage) {
|
||||
getStorage(ienv, storage);
|
||||
}
|
||||
|
||||
RenderingRuleSearchRequest* initSearchRequest(JNIEnv* env, jobject renderingRuleSearchRequest) {
|
||||
jobject storage = env->GetObjectField(renderingRuleSearchRequest, RenderingRuleSearchRequest_storage);
|
||||
RenderingRulesStorage* st = getStorage(env, storage);
|
||||
env->DeleteLocalRef(storage);
|
||||
RenderingRuleSearchRequest* res = new RenderingRuleSearchRequest(st);
|
||||
initRenderingRuleSearchRequest(env, res, renderingRuleSearchRequest);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL Java_net_osmand_NativeLibrary_searchNativeObjectsForRendering(JNIEnv* ienv,
|
||||
jobject obj, jint sleft, jint sright, jint stop, jint sbottom, jint zoom,
|
||||
jobject renderingRuleSearchRequest, bool skipDuplicates, int renderRouteDataFile,
|
||||
jobject objInterrupted, jstring msgNothingFound) {
|
||||
RenderingRuleSearchRequest* req = initSearchRequest(ienv, renderingRuleSearchRequest);
|
||||
jfieldID interruptedField = 0;
|
||||
if(objInterrupted != NULL) {
|
||||
jclass clObjInterrupted = ienv->GetObjectClass(objInterrupted);
|
||||
interruptedField = getFid(ienv, clObjInterrupted, "interrupted", "Z");
|
||||
ienv->DeleteLocalRef(clObjInterrupted);
|
||||
}
|
||||
|
||||
ResultJNIPublisher* j = new ResultJNIPublisher( objInterrupted, interruptedField, ienv);
|
||||
SearchQuery q(sleft, sright, stop, sbottom, req, j);
|
||||
q.zoom = zoom;
|
||||
|
||||
|
||||
ResultPublisher* res = searchObjectsForRendering(&q, skipDuplicates, renderRouteDataFile, getString(ienv, msgNothingFound));
|
||||
delete req;
|
||||
return (jlong) j;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////
|
||||
///////////// JNI RENDERING //////////////
|
||||
void fillRenderingAttributes(JNIRenderingContext& rc, RenderingRuleSearchRequest* req) {
|
||||
req->clearState();
|
||||
req->setIntFilter(req->props()->R_MINZOOM, rc.getZoom());
|
||||
if (req->searchRenderingAttribute("defaultColor")) {
|
||||
rc.setDefaultColor(req->getIntPropertyValue(req->props()->R_ATTR_COLOR_VALUE));
|
||||
}
|
||||
req->clearState();
|
||||
req->setIntFilter(req->props()->R_MINZOOM, rc.getZoom());
|
||||
if (req->searchRenderingAttribute("shadowRendering")) {
|
||||
rc.setShadowRenderingMode(req->getIntPropertyValue(req->props()->R_ATTR_INT_VALUE));
|
||||
rc.setShadowRenderingColor(req->getIntPropertyValue(req->props()->R_SHADOW_COLOR));
|
||||
}
|
||||
req->clearState();
|
||||
req->setIntFilter(req->props()->R_MINZOOM, rc.getZoom());
|
||||
if (req->searchRenderingAttribute("polygonMinSizeToDisplay")) {
|
||||
rc.polygonMinSizeToDisplay = req->getIntPropertyValue(req->props()->R_ATTR_INT_VALUE);
|
||||
}
|
||||
req->clearState();
|
||||
req->setIntFilter(req->props()->R_MINZOOM, rc.getZoom());
|
||||
if (req->searchRenderingAttribute("roadDensityZoomTile")) {
|
||||
rc.roadDensityZoomTile = req->getIntPropertyValue(req->props()->R_ATTR_INT_VALUE);
|
||||
}
|
||||
req->clearState();
|
||||
req->setIntFilter(req->props()->R_MINZOOM, rc.getZoom());
|
||||
if (req->searchRenderingAttribute("roadsDensityLimitPerTile")) {
|
||||
rc.roadsDensityLimitPerTile = req->getIntPropertyValue(req->props()->R_ATTR_INT_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ANDROID_BUILD
|
||||
#include <android/bitmap.h>
|
||||
|
||||
extern "C" JNIEXPORT jobject JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_generateRenderingDirect( JNIEnv* ienv, jobject obj,
|
||||
jobject renderingContext, jlong searchResult, jobject targetBitmap, jobject renderingRuleSearchRequest) {
|
||||
|
||||
// libJniGraphics interface
|
||||
typedef int (*PTR_AndroidBitmap_getInfo)(JNIEnv*, jobject, AndroidBitmapInfo*);
|
||||
typedef int (*PTR_AndroidBitmap_lockPixels)(JNIEnv*, jobject, void**);
|
||||
typedef int (*PTR_AndroidBitmap_unlockPixels)(JNIEnv*, jobject);
|
||||
static PTR_AndroidBitmap_getInfo dl_AndroidBitmap_getInfo = 0;
|
||||
static PTR_AndroidBitmap_lockPixels dl_AndroidBitmap_lockPixels = 0;
|
||||
static PTR_AndroidBitmap_unlockPixels dl_AndroidBitmap_unlockPixels = 0;
|
||||
static void* module_libjnigraphics = 0;
|
||||
|
||||
if(!module_libjnigraphics)
|
||||
{
|
||||
module_libjnigraphics = dlopen("jnigraphics", /*RTLD_NOLOAD*/0x0004);
|
||||
if(!module_libjnigraphics) {
|
||||
osmand_log_print(LOG_WARN, "jnigraphics was not found in loaded libraries");
|
||||
module_libjnigraphics = dlopen("jnigraphics", RTLD_NOW);
|
||||
}
|
||||
if(!module_libjnigraphics) {
|
||||
osmand_log_print(LOG_WARN, "jnigraphics was not loaded in default location");
|
||||
module_libjnigraphics = dlopen("/system/lib/libjnigraphics.so", RTLD_NOW);
|
||||
}
|
||||
if(!module_libjnigraphics)
|
||||
{
|
||||
osmand_log_print(LOG_ERROR, "Failed to load jnigraphics via dlopen, will going to crash");
|
||||
return NULL;
|
||||
}
|
||||
dl_AndroidBitmap_getInfo = (PTR_AndroidBitmap_getInfo)dlsym(module_libjnigraphics, "AndroidBitmap_getInfo");
|
||||
dl_AndroidBitmap_lockPixels = (PTR_AndroidBitmap_lockPixels)dlsym(module_libjnigraphics, "AndroidBitmap_lockPixels");
|
||||
dl_AndroidBitmap_unlockPixels = (PTR_AndroidBitmap_unlockPixels)dlsym(module_libjnigraphics, "AndroidBitmap_unlockPixels");
|
||||
}
|
||||
|
||||
// Gain information about bitmap
|
||||
AndroidBitmapInfo bitmapInfo;
|
||||
if(dl_AndroidBitmap_getInfo(ienv, targetBitmap, &bitmapInfo) != ANDROID_BITMAP_RESUT_SUCCESS)
|
||||
osmand_log_print(LOG_ERROR, "Failed to execute AndroidBitmap_getInfo");
|
||||
|
||||
osmand_log_print(LOG_INFO, "Creating SkBitmap in native w:%d h:%d s:%d f:%d!", bitmapInfo.width, bitmapInfo.height, bitmapInfo.stride, bitmapInfo.format);
|
||||
|
||||
SkBitmap* bitmap = new SkBitmap();
|
||||
if(bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
|
||||
int rowBytes = bitmapInfo.stride;
|
||||
osmand_log_print(LOG_INFO, "Row bytes for RGBA_8888 is %d", rowBytes);
|
||||
bitmap->setConfig(SkBitmap::kARGB_8888_Config, bitmapInfo.width, bitmapInfo.height, rowBytes);
|
||||
} else if(bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGB_565) {
|
||||
int rowBytes = bitmapInfo.stride;
|
||||
osmand_log_print(LOG_INFO, "Row bytes for RGB_565 is %d", rowBytes);
|
||||
bitmap->setConfig(SkBitmap::kRGB_565_Config, bitmapInfo.width, bitmapInfo.height, rowBytes);
|
||||
} else {
|
||||
osmand_log_print(LOG_ERROR, "Unknown target bitmap format");
|
||||
}
|
||||
|
||||
void* lockedBitmapData = NULL;
|
||||
if(dl_AndroidBitmap_lockPixels(ienv, targetBitmap, &lockedBitmapData) != ANDROID_BITMAP_RESUT_SUCCESS || !lockedBitmapData) {
|
||||
osmand_log_print(LOG_ERROR, "Failed to execute AndroidBitmap_lockPixels");
|
||||
}
|
||||
osmand_log_print(LOG_INFO, "Locked %d bytes at %p", bitmap->getSize(), lockedBitmapData);
|
||||
|
||||
bitmap->setPixels(lockedBitmapData);
|
||||
|
||||
osmand_log_print(LOG_INFO, "Initializing rendering");
|
||||
ElapsedTimer initObjects;
|
||||
initObjects.start();
|
||||
|
||||
RenderingRuleSearchRequest* req = initSearchRequest(ienv, renderingRuleSearchRequest);
|
||||
JNIRenderingContext rc;
|
||||
pullFromJavaRenderingContext(ienv, renderingContext, &rc);
|
||||
ResultPublisher* result = ((ResultPublisher*) searchResult);
|
||||
fillRenderingAttributes(rc, req);
|
||||
osmand_log_print(LOG_INFO, "Rendering image");
|
||||
initObjects.pause();
|
||||
|
||||
|
||||
// Main part do rendering
|
||||
rc.nativeOperations.start();
|
||||
SkCanvas* canvas = new SkCanvas(*bitmap);
|
||||
canvas->drawColor(rc.getDefaultColor());
|
||||
if(result != NULL) {
|
||||
doRendering(result->result, canvas, req, &rc);
|
||||
}
|
||||
|
||||
rc.nativeOperations.pause();
|
||||
|
||||
pushToJavaRenderingContext(ienv, renderingContext, &rc);
|
||||
osmand_log_print(LOG_INFO, "End Rendering image");
|
||||
if(dl_AndroidBitmap_unlockPixels(ienv, targetBitmap) != ANDROID_BITMAP_RESUT_SUCCESS) {
|
||||
osmand_log_print(LOG_ERROR, "Failed to execute AndroidBitmap_unlockPixels");
|
||||
}
|
||||
|
||||
// delete variables
|
||||
delete canvas;
|
||||
delete req;
|
||||
delete bitmap;
|
||||
// deleteObjects(mapDataObjects);
|
||||
|
||||
jclass resultClass = findClass(ienv, "net/osmand/NativeLibrary$RenderingGenerationResult");
|
||||
|
||||
jmethodID resultClassCtorId = ienv->GetMethodID(resultClass, "<init>", "(Ljava/nio/ByteBuffer;)V");
|
||||
|
||||
#ifdef DEBUG_NAT_OPERATIONS
|
||||
osmand_log_print(LOG_INFO, LOG_TAG,"Native ok (init %d, native op %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
|
||||
#else
|
||||
osmand_log_print(LOG_INFO, "Native ok (init %d, rendering %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
|
||||
#endif
|
||||
|
||||
/* Construct a result object */
|
||||
jobject resultObject = ienv->NewObject(resultClass, resultClassCtorId, NULL);
|
||||
|
||||
return resultObject;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void* bitmapData = NULL;
|
||||
size_t bitmapDataSize = 0;
|
||||
extern "C" JNIEXPORT jobject JNICALL Java_net_osmand_NativeLibrary_generateRenderingIndirect( JNIEnv* ienv,
|
||||
jobject obj, jobject renderingContext, jlong searchResult, jboolean isTransparent,
|
||||
jobject renderingRuleSearchRequest, jboolean encodePNG) {
|
||||
|
||||
JNIRenderingContext rc;
|
||||
pullFromJavaRenderingContext(ienv, renderingContext, &rc);
|
||||
|
||||
osmand_log_print(LOG_INFO, "Creating SkBitmap in native w:%d h:%d!", rc.getWidth(), rc.getHeight());
|
||||
|
||||
SkBitmap* bitmap = new SkBitmap();
|
||||
if (isTransparent == JNI_TRUE)
|
||||
bitmap->setConfig(SkBitmap::kARGB_8888_Config, rc.getWidth(), rc.getHeight(), 0);
|
||||
else
|
||||
bitmap->setConfig(SkBitmap::kRGB_565_Config, rc.getWidth(), rc.getHeight(), 0);
|
||||
|
||||
if (bitmapData != NULL && bitmapDataSize != bitmap->getSize()) {
|
||||
free(bitmapData);
|
||||
bitmapData = NULL;
|
||||
bitmapDataSize = 0;
|
||||
}
|
||||
if (bitmapData == NULL && bitmapDataSize == 0) {
|
||||
bitmapDataSize = bitmap->getSize();
|
||||
bitmapData = malloc(bitmapDataSize);
|
||||
osmand_log_print(LOG_INFO, "Allocated %d bytes at %p", bitmapDataSize, bitmapData);
|
||||
}
|
||||
|
||||
bitmap->setPixels(bitmapData);
|
||||
ElapsedTimer initObjects;
|
||||
initObjects.start();
|
||||
|
||||
RenderingRuleSearchRequest* req = initSearchRequest(ienv, renderingRuleSearchRequest);
|
||||
|
||||
ResultPublisher* result = ((ResultPublisher*) searchResult);
|
||||
// std::vector <BaseMapDataObject* > mapDataObjects = marshalObjects(binaryMapDataObjects);
|
||||
|
||||
initObjects.pause();
|
||||
// Main part do rendering
|
||||
fillRenderingAttributes(rc, req);
|
||||
|
||||
|
||||
SkCanvas* canvas = new SkCanvas(*bitmap);
|
||||
canvas->drawColor(rc.getDefaultColor());
|
||||
if (result != NULL) {
|
||||
doRendering(result->result, canvas, req, &rc);
|
||||
}
|
||||
pushToJavaRenderingContext(ienv, renderingContext, &rc);
|
||||
|
||||
jclass resultClass = findClass(ienv, "net/osmand/NativeLibrary$RenderingGenerationResult");
|
||||
|
||||
jmethodID resultClassCtorId = ienv->GetMethodID(resultClass, "<init>", "(Ljava/nio/ByteBuffer;)V");
|
||||
|
||||
#ifdef DEBUG_NAT_OPERATIONS
|
||||
osmand_log_print(LOG_INFO, "Native ok (init %d, native op %d) ", initObjects.getElapsedTime(), rc.nativeOperations.getElapsedTime());
|
||||
#else
|
||||
osmand_log_print(LOG_INFO, "Native ok (init %d, rendering %d) ", initObjects.getElapsedTime(),
|
||||
rc.nativeOperations.getElapsedTime());
|
||||
#endif
|
||||
// Allocate ctor paramters
|
||||
jobject bitmapBuffer;
|
||||
if(encodePNG) {
|
||||
SkImageEncoder* enc = SkImageEncoder::Create(SkImageEncoder::kPNG_Type);
|
||||
SkDynamicMemoryWStream* stream = new SkDynamicMemoryWStream();
|
||||
enc->encodeStream(stream, *bitmap, 80);
|
||||
// clean previous data
|
||||
free(bitmapData);
|
||||
bitmapDataSize = stream->bytesWritten();
|
||||
bitmapData = malloc(bitmapDataSize);
|
||||
|
||||
stream->copyTo(bitmapData);
|
||||
delete enc;
|
||||
}
|
||||
bitmapBuffer = ienv->NewDirectByteBuffer(bitmapData, bitmapDataSize);
|
||||
|
||||
// delete variables
|
||||
delete canvas;
|
||||
delete req;
|
||||
delete bitmap;
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
/* Construct a result object */
|
||||
jobject resultObject = ienv->NewObject(resultClass, resultClassCtorId, bitmapBuffer);
|
||||
|
||||
return resultObject;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
////////// JNI Rendering Context //////////////
|
||||
|
||||
jclass jclass_JUnidecode;
|
||||
jclass jclass_Reshaper;
|
||||
jmethodID jmethod_JUnidecode_unidecode;
|
||||
jmethodID jmethod_Reshaper_reshape;
|
||||
jclass jclass_RouteCalculationProgress = NULL;
|
||||
jfieldID jfield_RouteCalculationProgress_segmentNotFound = NULL;
|
||||
jfieldID jfield_RouteCalculationProgress_distanceFromBegin = NULL;
|
||||
jfieldID jfield_RouteCalculationProgress_directSegmentQueueSize = NULL;
|
||||
jfieldID jfield_RouteCalculationProgress_distanceFromEnd = NULL;
|
||||
jfieldID jfield_RouteCalculationProgress_reverseSegmentQueueSize = NULL;
|
||||
jfieldID jfield_RouteCalculationProgress_isCancelled = NULL;
|
||||
|
||||
jclass jclass_RenderingContext = NULL;
|
||||
jfieldID jfield_RenderingContext_interrupted = NULL;
|
||||
jfieldID jfield_RenderingContext_leftX = NULL;
|
||||
jfieldID jfield_RenderingContext_topY = NULL;
|
||||
jfieldID jfield_RenderingContext_width = NULL;
|
||||
jfieldID jfield_RenderingContext_height = NULL;
|
||||
jfieldID jfield_RenderingContext_zoom = NULL;
|
||||
jfieldID jfield_RenderingContext_tileDivisor = NULL;
|
||||
jfieldID jfield_RenderingContext_rotate = NULL;
|
||||
jfieldID jfield_RenderingContext_useEnglishNames = NULL;
|
||||
jfieldID jfield_RenderingContext_pointCount = NULL;
|
||||
jfieldID jfield_RenderingContext_pointInsideCount = NULL;
|
||||
jfieldID jfield_RenderingContext_visible = NULL;
|
||||
jfieldID jfield_RenderingContext_allObjects = NULL;
|
||||
jfieldID jfield_RenderingContext_density = NULL;
|
||||
jfieldID jfield_RenderingContext_shadowRenderingMode = NULL;
|
||||
jfieldID jfield_RenderingContext_shadowRenderingColor = NULL;
|
||||
jfieldID jfield_RenderingContext_defaultColor = NULL;
|
||||
jfieldID jfield_RenderingContext_textRenderingTime = NULL;
|
||||
jfieldID jfield_RenderingContext_lastRenderedKey = NULL;
|
||||
|
||||
jmethodID jmethod_RenderingContext_getIconRawData = NULL;
|
||||
|
||||
jclass jclass_RouteDataObject = NULL;
|
||||
jfieldID jfield_RouteDataObject_types = NULL;
|
||||
jfieldID jfield_RouteDataObject_pointsX = NULL;
|
||||
jfieldID jfield_RouteDataObject_pointsY = NULL;
|
||||
jfieldID jfield_RouteDataObject_restrictions = NULL;
|
||||
jfieldID jfield_RouteDataObject_pointTypes = NULL;
|
||||
jfieldID jfield_RouteDataObject_id = NULL;
|
||||
jmethodID jmethod_RouteDataObject_init = NULL;
|
||||
|
||||
jclass jclass_NativeRouteSearchResult = NULL;
|
||||
jmethodID jmethod_NativeRouteSearchResult_init = NULL;
|
||||
|
||||
|
||||
jclass jclass_RouteSubregion = NULL;
|
||||
jfieldID jfield_RouteSubregion_length = NULL;
|
||||
jfieldID jfield_RouteSubregion_filePointer= NULL;
|
||||
jfieldID jfield_RouteSubregion_left = NULL;
|
||||
jfieldID jfield_RouteSubregion_right = NULL;
|
||||
jfieldID jfield_RouteSubregion_top = NULL;
|
||||
jfieldID jfield_RouteSubregion_bottom = NULL;
|
||||
jfieldID jfield_RouteSubregion_shiftToData = NULL;
|
||||
|
||||
jclass jclass_RouteRegion = NULL;
|
||||
jfieldID jfield_RouteRegion_length = NULL;
|
||||
jfieldID jfield_RouteRegion_filePointer= NULL;
|
||||
|
||||
jclass jclass_RouteSegmentResult = NULL;
|
||||
jclass jclass_RouteSegmentResultAr = NULL;
|
||||
jmethodID jmethod_RouteSegmentResult_ctor = NULL;
|
||||
jfieldID jfield_RouteSegmentResult_preAttachedRoutes = NULL;
|
||||
|
||||
|
||||
|
||||
void loadJniRenderingContext(JNIEnv* env)
|
||||
{
|
||||
jclass_RouteSegmentResult = findClass(env, "net/osmand/router/RouteSegmentResult");
|
||||
jclass_RouteSegmentResultAr = findClass(env, "[Lnet/osmand/router/RouteSegmentResult;");
|
||||
jmethod_RouteSegmentResult_ctor = env->GetMethodID(jclass_RouteSegmentResult,
|
||||
"<init>", "(Lnet/osmand/binary/RouteDataObject;II)V");
|
||||
jfield_RouteSegmentResult_preAttachedRoutes = getFid(env, jclass_RouteSegmentResult, "preAttachedRoutes",
|
||||
"[[Lnet/osmand/router/RouteSegmentResult;");
|
||||
|
||||
jclass_RouteCalculationProgress = findClass(env, "net/osmand/router/RouteCalculationProgress");
|
||||
jfield_RouteCalculationProgress_isCancelled = getFid(env, jclass_RouteCalculationProgress, "isCancelled", "Z");
|
||||
jfield_RouteCalculationProgress_segmentNotFound = getFid(env, jclass_RouteCalculationProgress, "segmentNotFound", "I");
|
||||
jfield_RouteCalculationProgress_distanceFromBegin = getFid(env, jclass_RouteCalculationProgress, "distanceFromBegin", "F");
|
||||
jfield_RouteCalculationProgress_distanceFromEnd = getFid(env, jclass_RouteCalculationProgress, "distanceFromEnd", "F");
|
||||
jfield_RouteCalculationProgress_directSegmentQueueSize = getFid(env, jclass_RouteCalculationProgress, "directSegmentQueueSize", "I");
|
||||
jfield_RouteCalculationProgress_reverseSegmentQueueSize = getFid(env, jclass_RouteCalculationProgress, "reverseSegmentQueueSize", "I");
|
||||
|
||||
jclass_RenderingContext = findClass(env, "net/osmand/RenderingContext");
|
||||
jfield_RenderingContext_interrupted = getFid(env, jclass_RenderingContext, "interrupted", "Z");
|
||||
jfield_RenderingContext_leftX = getFid(env, jclass_RenderingContext, "leftX", "F" );
|
||||
jfield_RenderingContext_topY = getFid(env, jclass_RenderingContext, "topY", "F" );
|
||||
jfield_RenderingContext_width = getFid(env, jclass_RenderingContext, "width", "I" );
|
||||
jfield_RenderingContext_height = getFid(env, jclass_RenderingContext, "height", "I" );
|
||||
jfield_RenderingContext_zoom = getFid(env, jclass_RenderingContext, "zoom", "I" );
|
||||
jfield_RenderingContext_tileDivisor = getFid(env, jclass_RenderingContext, "tileDivisor", "F" );
|
||||
jfield_RenderingContext_rotate = getFid(env, jclass_RenderingContext, "rotate", "F" );
|
||||
jfield_RenderingContext_useEnglishNames = getFid(env, jclass_RenderingContext, "useEnglishNames", "Z" );
|
||||
jfield_RenderingContext_pointCount = getFid(env, jclass_RenderingContext, "pointCount", "I" );
|
||||
jfield_RenderingContext_pointInsideCount = getFid(env, jclass_RenderingContext, "pointInsideCount", "I" );
|
||||
jfield_RenderingContext_visible = getFid(env, jclass_RenderingContext, "visible", "I" );
|
||||
jfield_RenderingContext_allObjects = getFid(env, jclass_RenderingContext, "allObjects", "I" );
|
||||
jfield_RenderingContext_density = getFid(env, jclass_RenderingContext, "density", "F" );
|
||||
jfield_RenderingContext_shadowRenderingMode = getFid(env, jclass_RenderingContext, "shadowRenderingMode", "I" );
|
||||
jfield_RenderingContext_shadowRenderingColor = getFid(env, jclass_RenderingContext, "shadowRenderingColor", "I" );
|
||||
jfield_RenderingContext_defaultColor = getFid(env, jclass_RenderingContext, "defaultColor", "I" );
|
||||
jfield_RenderingContext_textRenderingTime = getFid(env, jclass_RenderingContext, "textRenderingTime", "I" );
|
||||
jfield_RenderingContext_lastRenderedKey = getFid(env, jclass_RenderingContext, "lastRenderedKey", "I" );
|
||||
jmethod_RenderingContext_getIconRawData = env->GetMethodID(jclass_RenderingContext,
|
||||
"getIconRawData", "(Ljava/lang/String;)[B");
|
||||
|
||||
jmethod_Object_toString = env->GetMethodID(findClass(env, "java/lang/Object", true),
|
||||
"toString", "()Ljava/lang/String;");
|
||||
|
||||
|
||||
jclass_JUnidecode = findClass(env, "net/sf/junidecode/Junidecode");
|
||||
jmethod_JUnidecode_unidecode = env->GetStaticMethodID(jclass_JUnidecode, "unidecode", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
jclass_Reshaper = findClass(env, "net/osmand/Reshaper");
|
||||
jmethod_Reshaper_reshape = env->GetStaticMethodID(jclass_Reshaper, "reshape", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||
|
||||
jclass_RouteDataObject = findClass(env, "net/osmand/binary/RouteDataObject");
|
||||
jclass_NativeRouteSearchResult = findClass(env, "net/osmand/NativeLibrary$NativeRouteSearchResult");
|
||||
jmethod_NativeRouteSearchResult_init = env->GetMethodID(jclass_NativeRouteSearchResult, "<init>", "(J[Lnet/osmand/binary/RouteDataObject;)V");
|
||||
|
||||
jfield_RouteDataObject_types = getFid(env, jclass_RouteDataObject, "types", "[I" );
|
||||
jfield_RouteDataObject_pointsX = getFid(env, jclass_RouteDataObject, "pointsX", "[I" );
|
||||
jfield_RouteDataObject_pointsY = getFid(env, jclass_RouteDataObject, "pointsY", "[I" );
|
||||
jfield_RouteDataObject_restrictions = getFid(env, jclass_RouteDataObject, "restrictions", "[J" );
|
||||
jfield_RouteDataObject_pointTypes = getFid(env, jclass_RouteDataObject, "pointTypes", "[[I" );
|
||||
jfield_RouteDataObject_id = getFid(env, jclass_RouteDataObject, "id", "J" );
|
||||
jmethod_RouteDataObject_init = env->GetMethodID(jclass_RouteDataObject, "<init>", "(Lnet/osmand/binary/BinaryMapRouteReaderAdapter$RouteRegion;[I[Ljava/lang/String;)V");
|
||||
|
||||
|
||||
jclass_RouteRegion = findClass(env, "net/osmand/binary/BinaryMapRouteReaderAdapter$RouteRegion");
|
||||
jfield_RouteRegion_length= getFid(env, jclass_RouteRegion, "length", "I" );
|
||||
jfield_RouteRegion_filePointer= getFid(env, jclass_RouteRegion, "filePointer", "I" );
|
||||
|
||||
jclass_RouteSubregion = findClass(env, "net/osmand/binary/BinaryMapRouteReaderAdapter$RouteSubregion");
|
||||
jfield_RouteSubregion_length= getFid(env, jclass_RouteSubregion, "length", "I" );
|
||||
jfield_RouteSubregion_filePointer= getFid(env, jclass_RouteSubregion, "filePointer", "I" );
|
||||
jfield_RouteSubregion_left= getFid(env, jclass_RouteSubregion, "left", "I" );
|
||||
jfield_RouteSubregion_right= getFid(env, jclass_RouteSubregion, "right", "I" );
|
||||
jfield_RouteSubregion_top= getFid(env, jclass_RouteSubregion, "top", "I" );
|
||||
jfield_RouteSubregion_bottom= getFid(env, jclass_RouteSubregion, "bottom", "I" );
|
||||
jfield_RouteSubregion_shiftToData= getFid(env, jclass_RouteSubregion, "shiftToData", "I" );
|
||||
// public final RouteRegion routeReg;
|
||||
|
||||
}
|
||||
|
||||
void pullFromJavaRenderingContext(JNIEnv* env, jobject jrc, JNIRenderingContext* rc)
|
||||
{
|
||||
rc->env = env;
|
||||
rc->setLocation(env->GetFloatField( jrc, jfield_RenderingContext_leftX ), env->GetFloatField( jrc, jfield_RenderingContext_topY ));
|
||||
rc->setDimension(env->GetIntField( jrc, jfield_RenderingContext_width ), env->GetIntField( jrc, jfield_RenderingContext_height ));
|
||||
|
||||
rc->setZoom(env->GetIntField( jrc, jfield_RenderingContext_zoom ));
|
||||
rc->setTileDivisor(env->GetFloatField( jrc, jfield_RenderingContext_tileDivisor ));
|
||||
rc->setRotate(env->GetFloatField( jrc, jfield_RenderingContext_rotate ));
|
||||
rc->setDensityScale(env->GetFloatField( jrc, jfield_RenderingContext_density ));
|
||||
rc->setUseEnglishNames(env->GetBooleanField( jrc, jfield_RenderingContext_useEnglishNames ));
|
||||
rc->javaRenderingContext = jrc;
|
||||
}
|
||||
|
||||
|
||||
// ElapsedTimer routingTimer;
|
||||
|
||||
jobject convertRouteDataObjectToJava(JNIEnv* ienv, RouteDataObject* route, jobject reg) {
|
||||
jintArray nameInts = ienv->NewIntArray(route->names.size());
|
||||
jobjectArray nameStrings = ienv->NewObjectArray(route->names.size(), jclassString, NULL);
|
||||
jint ar[route->names.size()];
|
||||
UNORDERED(map)<int, std::string >::iterator itNames = route->names.begin();
|
||||
jsize sz = 0;
|
||||
for (; itNames != route->names.end(); itNames++, sz++) {
|
||||
std::string name = itNames->second;
|
||||
jstring js = ienv->NewStringUTF(name.c_str());
|
||||
ienv->SetObjectArrayElement(nameStrings, sz, js);
|
||||
ienv->DeleteLocalRef(js);
|
||||
ar[sz] = itNames->first;
|
||||
}
|
||||
ienv->SetIntArrayRegion(nameInts, 0, route->names.size(), ar);
|
||||
jobject robj = ienv->NewObject(jclass_RouteDataObject, jmethod_RouteDataObject_init, reg, nameInts, nameStrings);
|
||||
ienv->DeleteLocalRef(nameInts);
|
||||
ienv->DeleteLocalRef(nameStrings);
|
||||
|
||||
ienv->SetLongField(robj, jfield_RouteDataObject_id, route->id);
|
||||
|
||||
jintArray types = ienv->NewIntArray(route->types.size());
|
||||
if (route->types.size() > 0) {
|
||||
ienv->SetIntArrayRegion(types, 0, route->types.size(), (jint*) &route->types[0]);
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_types, types);
|
||||
ienv->DeleteLocalRef(types);
|
||||
|
||||
jintArray pointsX = ienv->NewIntArray(route->pointsX.size());
|
||||
if (route->pointsX.size() > 0) {
|
||||
ienv->SetIntArrayRegion(pointsX, 0, route->pointsX.size(), (jint*) &route->pointsX[0]);
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_pointsX, pointsX);
|
||||
ienv->DeleteLocalRef(pointsX);
|
||||
|
||||
jintArray pointsY = ienv->NewIntArray(route->pointsY.size());
|
||||
if (route->pointsY.size() > 0) {
|
||||
ienv->SetIntArrayRegion(pointsY, 0, route->pointsY.size(), (jint*) &route->pointsY[0]);
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_pointsY, pointsY);
|
||||
ienv->DeleteLocalRef(pointsY);
|
||||
|
||||
jlongArray restrictions = ienv->NewLongArray(route->restrictions.size());
|
||||
if (route->restrictions.size() > 0) {
|
||||
ienv->SetLongArrayRegion(restrictions, 0, route->restrictions.size(), (jlong*) &route->restrictions[0]);
|
||||
}
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_restrictions, restrictions);
|
||||
ienv->DeleteLocalRef(restrictions);
|
||||
|
||||
jobjectArray pointTypes = ienv->NewObjectArray(route->pointTypes.size(), jclassIntArray, NULL);
|
||||
for (jint k = 0; k < route->pointTypes.size(); k++) {
|
||||
std::vector<uint32_t> ts = route->pointTypes[k];
|
||||
if (ts.size() > 0) {
|
||||
jintArray tos = ienv->NewIntArray(ts.size());
|
||||
ienv->SetIntArrayRegion(tos, 0, ts.size(), (jint*) &ts[0]);
|
||||
ienv->SetObjectArrayElement(pointTypes, k, tos);
|
||||
ienv->DeleteLocalRef(tos);
|
||||
}
|
||||
}
|
||||
|
||||
ienv->SetObjectField(robj, jfield_RouteDataObject_pointTypes, pointTypes);
|
||||
ienv->DeleteLocalRef(pointTypes);
|
||||
return robj;
|
||||
}
|
||||
|
||||
jobject convertRouteSegmentResultToJava(JNIEnv* ienv, RouteSegmentResult& r, UNORDERED(map)<int64_t, int>& indexes,
|
||||
jobjectArray regions) {
|
||||
RouteDataObject* rdo = r.object.get();
|
||||
jobject reg = NULL;
|
||||
int64_t fp = rdo->region->filePointer;
|
||||
int64_t ln = rdo->region->length;
|
||||
if(indexes.find((fp <<31) + ln) != indexes.end()) {
|
||||
reg = ienv->GetObjectArrayElement(regions, indexes[(fp <<31) + ln]);
|
||||
}
|
||||
jobjectArray ar = ienv->NewObjectArray(r.attachedRoutes.size(), jclass_RouteSegmentResultAr, NULL);
|
||||
for(jsize k = 0; k < r.attachedRoutes.size(); k++) {
|
||||
jobjectArray art = ienv->NewObjectArray(r.attachedRoutes[k].size(), jclass_RouteSegmentResult, NULL);
|
||||
for(jsize kj = 0; kj < r.attachedRoutes[k].size(); kj++) {
|
||||
jobject jo = convertRouteSegmentResultToJava(ienv, r.attachedRoutes[k][kj], indexes, regions);
|
||||
ienv->SetObjectArrayElement(art, kj, jo);
|
||||
ienv->DeleteLocalRef(jo);
|
||||
}
|
||||
ienv->SetObjectArrayElement(ar, k, art);
|
||||
ienv->DeleteLocalRef(art);
|
||||
}
|
||||
jobject robj = convertRouteDataObjectToJava(ienv, rdo, reg);
|
||||
jobject resobj = ienv->NewObject(jclass_RouteSegmentResult, jmethod_RouteSegmentResult_ctor, robj,
|
||||
r.startPointIndex, r.endPointIndex);
|
||||
ienv->SetObjectField(resobj, jfield_RouteSegmentResult_preAttachedRoutes, ar);
|
||||
if(reg != NULL) {
|
||||
ienv->DeleteLocalRef(reg);
|
||||
}
|
||||
ienv->DeleteLocalRef(robj);
|
||||
ienv->DeleteLocalRef(ar);
|
||||
return resobj;
|
||||
}
|
||||
|
||||
class NativeRoutingTile {
|
||||
public:
|
||||
std::vector<RouteDataObject*> result;
|
||||
UNORDERED(map)<uint64_t, std::vector<RouteDataObject*> > cachedByLocations;
|
||||
};
|
||||
|
||||
|
||||
// protected static native void deleteRouteSearchResult(long searchResultHandle!);
|
||||
extern "C" JNIEXPORT void JNICALL Java_net_osmand_NativeLibrary_deleteRouteSearchResult(JNIEnv* ienv,
|
||||
jobject obj, jlong ref) {
|
||||
NativeRoutingTile* t = (NativeRoutingTile*) ref;
|
||||
for (unsigned int i = 0; i < t->result.size(); i++) {
|
||||
delete t->result[i];
|
||||
t->result[i] = NULL;
|
||||
}
|
||||
delete t;
|
||||
}
|
||||
|
||||
class RouteCalculationProgressWrapper: public RouteCalculationProgress {
|
||||
jobject j;
|
||||
JNIEnv* ienv;
|
||||
public:
|
||||
RouteCalculationProgressWrapper(JNIEnv* ienv, jobject j) : RouteCalculationProgress(),
|
||||
ienv(ienv), j(j) {
|
||||
}
|
||||
virtual bool isCancelled() {
|
||||
return ienv->GetBooleanField(j, jfield_RouteCalculationProgress_isCancelled);
|
||||
}
|
||||
virtual void setSegmentNotFound(int s) {
|
||||
ienv->SetIntField(j, jfield_RouteCalculationProgress_segmentNotFound, s);
|
||||
}
|
||||
virtual void updateStatus(float distanceFromBegin, int directSegmentQueueSize, float distanceFromEnd,
|
||||
int reverseSegmentQueueSize) {
|
||||
RouteCalculationProgress::updateStatus(distanceFromBegin, directSegmentQueueSize,
|
||||
distanceFromEnd, reverseSegmentQueueSize);
|
||||
ienv->SetFloatField(j, jfield_RouteCalculationProgress_distanceFromBegin, this->distanceFromBegin);
|
||||
ienv->SetFloatField(j, jfield_RouteCalculationProgress_distanceFromEnd, this->distanceFromEnd);
|
||||
ienv->SetIntField(j, jfield_RouteCalculationProgress_directSegmentQueueSize, this->directSegmentQueueSize);
|
||||
ienv->SetIntField(j, jfield_RouteCalculationProgress_reverseSegmentQueueSize, this->reverseSegmentQueueSize);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
//p RouteSegmentResult[] nativeRouting(int[] coordinates, int[] state, String[] keyConfig, String[] valueConfig);
|
||||
extern "C" JNIEXPORT jobjectArray JNICALL Java_net_osmand_NativeLibrary_nativeRouting(JNIEnv* ienv,
|
||||
jobject obj, jintArray coordinates,
|
||||
jintArray stateConfig, jobjectArray keyConfig, jobjectArray valueConfig, jfloat initDirection,
|
||||
jobjectArray regions, jobject progress) {
|
||||
vector<ROUTE_TRIPLE> cfg;
|
||||
int* data = ienv->GetIntArrayElements(stateConfig, NULL);
|
||||
for(int k = 0; k < ienv->GetArrayLength(stateConfig); k++) {
|
||||
jstring kl = (jstring)ienv->GetObjectArrayElement(keyConfig, k);
|
||||
jstring vl = (jstring)ienv->GetObjectArrayElement(valueConfig, k);
|
||||
ROUTE_TRIPLE t = ROUTE_TRIPLE (data[k], std::pair<string, string>(
|
||||
getString(ienv, kl),
|
||||
getString(ienv, vl))
|
||||
);
|
||||
ienv->DeleteLocalRef(kl);
|
||||
ienv->DeleteLocalRef(vl);
|
||||
cfg.push_back(t);
|
||||
}
|
||||
ienv->ReleaseIntArrayElements(stateConfig, data, 0);
|
||||
|
||||
RoutingConfiguration config(cfg, initDirection);
|
||||
RoutingContext c(config);
|
||||
c.progress = SHARED_PTR<RouteCalculationProgress>(new RouteCalculationProgressWrapper(ienv, progress));
|
||||
data = ienv->GetIntArrayElements(coordinates, NULL);
|
||||
c.startX = data[0];
|
||||
c.startY = data[1];
|
||||
c.endX = data[2];
|
||||
c.endY = data[3];
|
||||
ienv->ReleaseIntArrayElements(coordinates, data, 0);
|
||||
vector<RouteSegmentResult> r = searchRouteInternal(&c, false);
|
||||
UNORDERED(map)<int64_t, int> indexes;
|
||||
for (int t = 0; t< ienv->GetArrayLength(regions); t++) {
|
||||
jobject oreg = ienv->GetObjectArrayElement(regions, t);
|
||||
int64_t fp = ienv->GetIntField(oreg, jfield_RouteRegion_filePointer);
|
||||
int64_t ln = ienv->GetIntField(oreg, jfield_RouteRegion_length);
|
||||
ienv->DeleteLocalRef(oreg);
|
||||
indexes[(fp <<31) + ln] = t;
|
||||
}
|
||||
|
||||
// convert results
|
||||
jobjectArray res = ienv->NewObjectArray(r.size(), jclass_RouteSegmentResult, NULL);
|
||||
for (int i = 0; i < r.size(); i++) {
|
||||
jobject resobj = convertRouteSegmentResultToJava(ienv, r[i], indexes, regions);
|
||||
ienv->SetObjectArrayElement(res, i, resobj);
|
||||
ienv->DeleteLocalRef(resobj);
|
||||
}
|
||||
if (r.size() == 0) {
|
||||
osmand_log_print(LOG_INFO, "No route found");
|
||||
}
|
||||
fflush(stdout);
|
||||
return res;
|
||||
}
|
||||
|
||||
// protected static native RouteDataObject[] getRouteDataObjects(NativeRouteSearchResult rs, int x31, int y31!);
|
||||
extern "C" JNIEXPORT jobjectArray JNICALL Java_net_osmand_NativeLibrary_getRouteDataObjects(JNIEnv* ienv,
|
||||
jobject obj, jobject reg, jlong ref, jint x31, jint y31) {
|
||||
|
||||
NativeRoutingTile* t = (NativeRoutingTile*) ref;
|
||||
uint64_t lr = ((uint64_t) x31 << 31) + y31;
|
||||
std::vector<RouteDataObject*> collected = t->cachedByLocations[lr];
|
||||
jobjectArray res = ienv->NewObjectArray(collected.size(), jclass_RouteDataObject, NULL);
|
||||
for (jint i = 0; i < collected.size(); i++) {
|
||||
jobject robj = convertRouteDataObjectToJava(ienv, collected[i], reg);
|
||||
ienv->SetObjectArrayElement(res, i, robj);
|
||||
ienv->DeleteLocalRef(robj);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//protected static native NativeRouteSearchResult loadRoutingData(RouteRegion reg, String regName, int regfp, RouteSubregion subreg,
|
||||
// boolean loadObjects);
|
||||
extern "C" JNIEXPORT jobject JNICALL Java_net_osmand_NativeLibrary_loadRoutingData(JNIEnv* ienv,
|
||||
jobject obj, jobject reg, jstring regName, jint regFilePointer,
|
||||
jobject subreg, jboolean loadObjects) {
|
||||
RoutingIndex ind;
|
||||
ind.filePointer = regFilePointer;
|
||||
ind.name = getString(ienv, regName);
|
||||
RouteSubregion sub(&ind);
|
||||
sub.filePointer = ienv->GetIntField(subreg, jfield_RouteSubregion_filePointer);
|
||||
sub.length = ienv->GetIntField(subreg, jfield_RouteSubregion_length);
|
||||
sub.left = ienv->GetIntField(subreg, jfield_RouteSubregion_left);
|
||||
sub.right = ienv->GetIntField(subreg, jfield_RouteSubregion_right);
|
||||
sub.top = ienv->GetIntField(subreg, jfield_RouteSubregion_top);
|
||||
sub.bottom = ienv->GetIntField(subreg, jfield_RouteSubregion_bottom);
|
||||
sub.mapDataBlock= ienv->GetIntField(subreg, jfield_RouteSubregion_shiftToData);
|
||||
std::vector<RouteDataObject*> result;
|
||||
SearchQuery q;
|
||||
searchRouteDataForSubRegion(&q, result, &sub);
|
||||
|
||||
|
||||
if (loadObjects) {
|
||||
jobjectArray res = ienv->NewObjectArray(result.size(), jclass_RouteDataObject, NULL);
|
||||
for (jint i = 0; i < result.size(); i++) {
|
||||
if (result[i] != NULL) {
|
||||
jobject robj = convertRouteDataObjectToJava(ienv, result[i], reg);
|
||||
ienv->SetObjectArrayElement(res, i, robj);
|
||||
ienv->DeleteLocalRef(robj);
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < result.size(); i++) {
|
||||
if (result[i] != NULL) {
|
||||
delete result[i];
|
||||
}
|
||||
result[i] = NULL;
|
||||
}
|
||||
return ienv->NewObject(jclass_NativeRouteSearchResult, jmethod_NativeRouteSearchResult_init, ((jlong) 0), res);
|
||||
} else {
|
||||
NativeRoutingTile* r = new NativeRoutingTile();
|
||||
for (jint i = 0; i < result.size(); i++) {
|
||||
if (result[i] != NULL) {
|
||||
r->result.push_back(result[i]);
|
||||
for (jint j = 0; j < result[i]->pointsX.size(); j++) {
|
||||
jint x = result[i]->pointsX[j];
|
||||
jint y = result[i]->pointsY[j];
|
||||
uint64_t lr = ((uint64_t) x << 31) + y;
|
||||
r->cachedByLocations[lr].push_back(result[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
jlong ref = (jlong) r;
|
||||
if(r->result.size() == 0) {
|
||||
ref = 0;
|
||||
delete r;
|
||||
}
|
||||
|
||||
return ienv->NewObject(jclass_NativeRouteSearchResult, jmethod_NativeRouteSearchResult_init, ref, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void pushToJavaRenderingContext(JNIEnv* env, jobject jrc, JNIRenderingContext* rc)
|
||||
{
|
||||
env->SetIntField( jrc, jfield_RenderingContext_pointCount, (jint) rc->pointCount);
|
||||
env->SetIntField( jrc, jfield_RenderingContext_pointInsideCount, (jint)rc->pointInsideCount);
|
||||
env->SetIntField( jrc, jfield_RenderingContext_visible, (jint)rc->visible);
|
||||
env->SetIntField( jrc, jfield_RenderingContext_allObjects, rc->allObjects);
|
||||
env->SetIntField( jrc, jfield_RenderingContext_textRenderingTime, rc->textRendering.getElapsedTime());
|
||||
env->SetIntField( jrc, jfield_RenderingContext_lastRenderedKey, rc->lastRenderedKey);
|
||||
}
|
||||
|
||||
bool JNIRenderingContext::interrupted()
|
||||
{
|
||||
return env->GetBooleanField(javaRenderingContext, jfield_RenderingContext_interrupted);
|
||||
}
|
||||
|
||||
SkBitmap* JNIRenderingContext::getCachedBitmap(const std::string& bitmapResource) {
|
||||
JNIEnv* env = this->env;
|
||||
jstring jstr = env->NewStringUTF(bitmapResource.c_str());
|
||||
jbyteArray javaIconRawData = (jbyteArray)env->CallObjectMethod(this->javaRenderingContext, jmethod_RenderingContext_getIconRawData, jstr);
|
||||
env->DeleteLocalRef(jstr);
|
||||
if(!javaIconRawData)
|
||||
return NULL;
|
||||
|
||||
jbyte* bitmapBuffer = env->GetByteArrayElements(javaIconRawData, NULL);
|
||||
jint bufferLen = env->GetArrayLength(javaIconRawData);
|
||||
|
||||
// Decode bitmap
|
||||
SkBitmap* iconBitmap = new SkBitmap();
|
||||
//TODO: JPEG is badly supported! At the moment it needs sdcard to be present (sic). Patch that
|
||||
if(!SkImageDecoder::DecodeMemory(bitmapBuffer, bufferLen, iconBitmap))
|
||||
{
|
||||
// Failed to decode
|
||||
delete iconBitmap;
|
||||
|
||||
this->nativeOperations.start();
|
||||
env->ReleaseByteArrayElements(javaIconRawData, bitmapBuffer, JNI_ABORT);
|
||||
env->DeleteLocalRef(javaIconRawData);
|
||||
|
||||
throwNewException(env, (std::string("Failed to decode ") + bitmapResource).c_str());
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
env->ReleaseByteArrayElements(javaIconRawData, bitmapBuffer, JNI_ABORT);
|
||||
env->DeleteLocalRef(javaIconRawData);
|
||||
|
||||
return iconBitmap;
|
||||
}
|
||||
|
||||
std::string JNIRenderingContext::getTranslatedString(const std::string& name) {
|
||||
if (this->isUsingEnglishNames()) {
|
||||
jstring n = this->env->NewStringUTF(name.c_str());
|
||||
jstring translate = (jstring) this->env->CallStaticObjectMethod(jclass_JUnidecode, jmethod_JUnidecode_unidecode, n);
|
||||
std::string res = getString(this->env, translate);
|
||||
this->env->DeleteLocalRef(translate);
|
||||
this->env->DeleteLocalRef(n);
|
||||
return res;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string JNIRenderingContext::getReshapedString(const std::string& name) {
|
||||
jstring n = this->env->NewStringUTF(name.c_str());
|
||||
jstring translate = (jstring) this->env->CallStaticObjectMethod(jclass_Reshaper, jmethod_Reshaper_reshape, n);
|
||||
std::string res = getString(this->env, translate);
|
||||
this->env->DeleteLocalRef(translate);
|
||||
this->env->DeleteLocalRef(n);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
#ifndef _JAVA_WRAP_H
|
||||
#define _JAVA_WRAP_H
|
||||
|
||||
#include "jni.h"
|
||||
#include "binaryRead.h"
|
||||
|
||||
struct ResultJNIPublisher : ResultPublisher {
|
||||
JNIEnv* env;
|
||||
jobject o;
|
||||
jfieldID interruptedField;
|
||||
ResultJNIPublisher(jobject o, jfieldID interruptedField, JNIEnv* env) :
|
||||
o(o), interruptedField(interruptedField), env(env){
|
||||
}
|
||||
|
||||
bool isCancelled() {
|
||||
if (env != NULL && o != NULL) {
|
||||
return env->GetBooleanField(o, interruptedField);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct JNIRenderingContext : RenderingContext
|
||||
{
|
||||
jobject javaRenderingContext;
|
||||
JNIEnv* env;
|
||||
JNIRenderingContext() : javaRenderingContext(NULL){
|
||||
}
|
||||
|
||||
virtual SkBitmap* getCachedBitmap(const std::string& bitmapResource);
|
||||
virtual std::string getTranslatedString(const std::string& src);
|
||||
virtual std::string getReshapedString(const std::string& src);
|
||||
|
||||
virtual bool interrupted();
|
||||
virtual ~JNIRenderingContext(){}
|
||||
};
|
||||
|
||||
void pullFromJavaRenderingContext(JNIEnv* env, jobject jrc, JNIRenderingContext* rc);
|
||||
void pushToJavaRenderingContext(JNIEnv* env, jobject jrc, JNIRenderingContext* rc);
|
||||
|
||||
jobject newGlobalRef(JNIEnv* env, jobject o)
|
||||
{
|
||||
return env->NewGlobalRef(o);
|
||||
}
|
||||
|
||||
void throwNewException(JNIEnv* env, const char* msg)
|
||||
{
|
||||
osmand_log_print(LOG_ERROR, msg);
|
||||
env->ThrowNew(env->FindClass("java/lang/Exception"), msg);
|
||||
}
|
||||
|
||||
jclass findClass(JNIEnv* env, const char* className, bool mustHave = true)
|
||||
{
|
||||
jclass javaClass = env->FindClass(className);
|
||||
if(!javaClass && mustHave)
|
||||
throwNewException(env, (std::string("Failed to find class ") + className).c_str());
|
||||
return (jclass)newGlobalRef(env, javaClass);
|
||||
}
|
||||
|
||||
|
||||
jfieldID getFid(JNIEnv* env, jclass cls, const char* fieldName, const char* sig)
|
||||
{
|
||||
jfieldID jfield = env->GetFieldID(cls, fieldName, sig);
|
||||
if(!jfield)
|
||||
throwNewException(env, (std::string("Failed to find field ") + fieldName + std::string(" with signature ") + sig).c_str());
|
||||
return jfield;
|
||||
}
|
||||
|
||||
std::string getStringField(JNIEnv* env, jobject o, jfieldID fid)
|
||||
{
|
||||
jstring jstr = (jstring)env->GetObjectField(o, fid);
|
||||
if(!jstr)
|
||||
{
|
||||
throwNewException(env, "Failed to get object from field");
|
||||
return std::string();
|
||||
}
|
||||
const char* utfBytes = env->GetStringUTFChars(jstr, NULL);
|
||||
//TODO: I'm not quite sure that if real unicode will happen here, this will work as expected
|
||||
std::string result(utfBytes);
|
||||
env->ReleaseStringUTFChars(jstr, utfBytes);
|
||||
env->DeleteLocalRef(jstr);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string getString(JNIEnv* env, jstring jstr)
|
||||
{
|
||||
if(!jstr)
|
||||
{
|
||||
throwNewException(env, "NULL jstring passed in");
|
||||
return std::string();
|
||||
}
|
||||
const char* utfBytes = env->GetStringUTFChars(jstr, NULL);
|
||||
//TODO: I'm not quite sure that if real unicode will happen here, this will work as expected
|
||||
std::string result(utfBytes);
|
||||
env->ReleaseStringUTFChars(jstr, utfBytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string getStringMethod(JNIEnv* env, jobject o, jmethodID fid)
|
||||
{
|
||||
jstring js = (jstring)env->CallObjectMethod(o, fid);
|
||||
std::string s = getString(env, js);
|
||||
env->DeleteLocalRef(js);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string getStringMethod(JNIEnv* env, jobject o, jmethodID fid, int i) {
|
||||
jstring js = (jstring) env->CallObjectMethod(o, fid, i);
|
||||
std::string s = getString(env, js);
|
||||
env->DeleteLocalRef(js);
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef _OSMAND_MAP_OBJECTS
|
||||
#define _OSMAND_MAP_OBJECTS
|
||||
|
||||
#include "common.h"
|
||||
#include "mapObjects.h"
|
||||
|
||||
void deleteObjects(std::vector <MapDataObject* > & v)
|
||||
{
|
||||
for(size_t i = 0; i< v.size(); i++)
|
||||
{
|
||||
delete v.at(i);
|
||||
}
|
||||
v.clear();
|
||||
}
|
||||
|
||||
#endif /*_OSMAND_MAP_OBJECTS*/
|
|
@ -1,94 +0,0 @@
|
|||
#ifndef _OSMAND_MAP_OBJECTS_H
|
||||
#define _OSMAND_MAP_OBJECTS_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <limits.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef pair<std::string, std::string> tag_value;
|
||||
typedef pair<int, int> int_pair;
|
||||
typedef vector< pair<int, int> > coordinates;
|
||||
|
||||
|
||||
class MapDataObject
|
||||
{
|
||||
static const unsigned int UNDEFINED_STRING = INT_MAX;
|
||||
public:
|
||||
|
||||
std::vector<tag_value> types;
|
||||
std::vector<tag_value> additionalTypes;
|
||||
coordinates points;
|
||||
std::vector < coordinates > polygonInnerCoordinates;
|
||||
|
||||
UNORDERED(map)< std::string, unsigned int> stringIds;
|
||||
|
||||
UNORDERED(map)< std::string, std::string > objectNames;
|
||||
bool area;
|
||||
long long id;
|
||||
|
||||
//
|
||||
|
||||
bool cycle(){
|
||||
return points[0] == points[points.size() -1];
|
||||
}
|
||||
bool containsAdditional(std::string key, std::string val) {
|
||||
std::vector<tag_value>::iterator it = additionalTypes.begin();
|
||||
while (it != additionalTypes.end()) {
|
||||
if (it->first == key && it->second == val) {
|
||||
return true;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool contains(std::string key, std::string val) {
|
||||
std::vector<tag_value>::iterator it = types.begin();
|
||||
while (it != types.end()) {
|
||||
if (it->first == key) {
|
||||
return it->second == val;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int getSimpleLayer() {
|
||||
std::vector<tag_value>::iterator it = additionalTypes.begin();
|
||||
bool tunnel = false;
|
||||
bool bridge = false;
|
||||
while (it != additionalTypes.end()) {
|
||||
if (it->first == "layer") {
|
||||
if(it->second.length() > 0) {
|
||||
if(it->second[0] == '-'){
|
||||
return -1;
|
||||
} else if (it->second[0] == '0'){
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else if (it->first == "tunnel") {
|
||||
tunnel = "yes" == it->second;
|
||||
} else if (it->first == "bridge") {
|
||||
bridge = "yes" == it->second;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
if (tunnel) {
|
||||
return -1;
|
||||
} else if (bridge) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
void deleteObjects(std::vector <MapDataObject* > & v);
|
||||
|
||||
|
||||
#endif /*_OSMAND_MAP_OBJECTS_H*/
|
|
@ -1,507 +0,0 @@
|
|||
#ifndef _MULTIPOLYGONS_CPP
|
||||
#define _MULTIPOLYGONS_CPP
|
||||
|
||||
#include "multipolygons.h"
|
||||
#include "osmand_log.h"
|
||||
|
||||
// returns true if coastlines were added!
|
||||
bool processCoastlines(std::vector<MapDataObject*>& coastLines, int leftX, int rightX, int bottomY, int topY, int zoom,
|
||||
bool showIfThereIncompleted, bool addDebugIncompleted, std::vector<MapDataObject*>& res) {
|
||||
std::vector<coordinates> completedRings;
|
||||
std::vector<coordinates > uncompletedRings;
|
||||
std::vector<MapDataObject*>::iterator val = coastLines.begin();
|
||||
long long dbId = 0;
|
||||
for (; val != coastLines.end(); val++) {
|
||||
MapDataObject* o = *val;
|
||||
int len = o->points.size();
|
||||
if (len < 2) {
|
||||
continue;
|
||||
}
|
||||
dbId = o->id >> 1;
|
||||
coordinates* cs = new coordinates();
|
||||
int px = o->points.at(0).first;
|
||||
int py = o->points.at(0).second;
|
||||
int x = px;
|
||||
int y = py;
|
||||
bool pinside = leftX <= x && x <= rightX && y >= topY && y <= bottomY;
|
||||
if (pinside) {
|
||||
cs->push_back(int_pair(x, y));
|
||||
}
|
||||
for (int i = 1; i < len; i++) {
|
||||
x = o->points.at(i).first;
|
||||
y = o->points.at(i).second;
|
||||
bool inside = leftX <= x && x <= rightX && y >= topY && y <= bottomY;
|
||||
bool lineEnded = calculateLineCoordinates(inside, x, y, pinside, px, py, leftX, rightX, bottomY, topY, *cs);
|
||||
if (lineEnded) {
|
||||
combineMultipolygonLine(completedRings, uncompletedRings, *cs);
|
||||
// create new line if it goes outside
|
||||
cs = new coordinates();
|
||||
}
|
||||
px = x;
|
||||
py = y;
|
||||
pinside = inside;
|
||||
}
|
||||
combineMultipolygonLine(completedRings, uncompletedRings, *cs);
|
||||
}
|
||||
if (completedRings.size() == 0 && uncompletedRings.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
if (uncompletedRings.size() > 0) {
|
||||
unifyIncompletedRings(uncompletedRings, completedRings, leftX, rightX, bottomY, topY, dbId, zoom);
|
||||
}
|
||||
if (addDebugIncompleted) {
|
||||
// draw uncompleted for debug purpose
|
||||
for (int i = 0; i < uncompletedRings.size(); i++) {
|
||||
MapDataObject* o = new MapDataObject();
|
||||
o->points = uncompletedRings[i];
|
||||
o->types.push_back(tag_value("natural", "coastline_broken"));
|
||||
res.push_back(o);
|
||||
}
|
||||
// draw completed for debug purpose
|
||||
for (int i = 0; i < completedRings.size(); i++) {
|
||||
MapDataObject* o = new MapDataObject();
|
||||
o->points = completedRings[i];
|
||||
o->types.push_back(tag_value("natural", "coastline_line"));
|
||||
res.push_back(o);
|
||||
}
|
||||
|
||||
}
|
||||
if (!showIfThereIncompleted && uncompletedRings.size() > 0) {
|
||||
return false;
|
||||
}
|
||||
bool clockwiseFound = false;
|
||||
for (int i = 0; i < completedRings.size(); i++) {
|
||||
bool clockwise = isClockwiseWay(completedRings[i]);
|
||||
clockwiseFound = clockwiseFound || clockwise;
|
||||
MapDataObject* o = new MapDataObject();
|
||||
o->points = completedRings[i];
|
||||
if (clockwise) {
|
||||
o->types.push_back(tag_value("natural", "coastline"));
|
||||
} else {
|
||||
o->types.push_back(tag_value("natural", "land"));
|
||||
}
|
||||
o->id = dbId;
|
||||
o->area = true;
|
||||
res.push_back(o);
|
||||
}
|
||||
|
||||
if (!clockwiseFound && uncompletedRings.size() == 0) {
|
||||
// add complete water tile
|
||||
MapDataObject* o = new MapDataObject();
|
||||
o->points.push_back(int_pair(leftX, topY));
|
||||
o->points.push_back(int_pair(rightX, topY));
|
||||
o->points.push_back(int_pair(rightX, bottomY));
|
||||
o->points.push_back(int_pair(leftX, bottomY));
|
||||
o->points.push_back(int_pair(leftX, topY));
|
||||
o->id = dbId;
|
||||
o->types.push_back(tag_value("natural", "coastline"));
|
||||
osmand_log_print(LOG_ERROR, "!!! Isolated islands !!!");
|
||||
res.push_back(o);
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Copied from MapAlgorithms
|
||||
int ray_intersect_x(int prevX, int prevY, int x, int y, int middleY) {
|
||||
// prev node above line
|
||||
// x,y node below line
|
||||
if (prevY > y) {
|
||||
int tx = x;
|
||||
int ty = y;
|
||||
x = prevX;
|
||||
y = prevY;
|
||||
prevX = tx;
|
||||
prevY = ty;
|
||||
}
|
||||
if (y == middleY || prevY == middleY) {
|
||||
middleY -= 1;
|
||||
}
|
||||
if (prevY > middleY || y < middleY) {
|
||||
return INT_MIN;
|
||||
} else {
|
||||
if (y == prevY) {
|
||||
// the node on the boundary !!!
|
||||
return x;
|
||||
}
|
||||
// that tested on all cases (left/right)
|
||||
double rx = x + ((double) middleY - y) * ((double) x - prevX) / (((double) y - prevY));
|
||||
return (int) rx;
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from MapAlgorithms
|
||||
bool isClockwiseWay(std::vector<int_pair>& c) {
|
||||
if (c.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// calculate middle Y
|
||||
long long middleY = 0;
|
||||
for (size_t i = 0; i < c.size(); i++) {
|
||||
middleY += c.at(i).second;
|
||||
}
|
||||
middleY /= (long long) c.size();
|
||||
|
||||
double clockwiseSum = 0;
|
||||
|
||||
bool firstDirectionUp = false;
|
||||
int previousX = INT_MIN;
|
||||
int firstX = INT_MIN;
|
||||
|
||||
int prevX = c.at(0).first;
|
||||
int prevY = c.at(0).second;
|
||||
|
||||
for (size_t i = 1; i < c.size(); i++) {
|
||||
int x = c.at(i).first;
|
||||
int y = c.at(i).second;
|
||||
int rX = ray_intersect_x(prevX, prevY, x, y, (int) middleY);
|
||||
if (rX != INT_MIN) {
|
||||
bool skipSameSide = (y <= middleY) == (prevY <= middleY);
|
||||
if (skipSameSide) {
|
||||
continue;
|
||||
}
|
||||
bool directionUp = prevY >= middleY;
|
||||
if (firstX == INT_MIN) {
|
||||
firstDirectionUp = directionUp;
|
||||
firstX = rX;
|
||||
} else {
|
||||
bool clockwise = (!directionUp) == (previousX < rX);
|
||||
if (clockwise) {
|
||||
clockwiseSum += abs(previousX - rX);
|
||||
} else {
|
||||
clockwiseSum -= abs(previousX - rX);
|
||||
}
|
||||
}
|
||||
previousX = rX;
|
||||
}
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
}
|
||||
|
||||
if (firstX != INT_MIN) {
|
||||
bool clockwise = (!firstDirectionUp) == (previousX < firstX);
|
||||
if (clockwise) {
|
||||
clockwiseSum += abs(previousX - firstX);
|
||||
} else {
|
||||
clockwiseSum -= abs(previousX - firstX);
|
||||
}
|
||||
}
|
||||
|
||||
return clockwiseSum >= 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void combineMultipolygonLine(std::vector<coordinates>& completedRings, std::vector<coordinates>& incompletedRings,
|
||||
coordinates& coordinates) {
|
||||
if (coordinates.size() > 0) {
|
||||
if (coordinates.at(0) == coordinates.at(coordinates.size() - 1)) {
|
||||
completedRings.push_back(coordinates);
|
||||
} else {
|
||||
bool add = true;
|
||||
for (size_t k = 0; k < incompletedRings.size();) {
|
||||
bool remove = false;
|
||||
std::vector<int_pair> i = incompletedRings.at(k);
|
||||
if (coordinates.at(0) == i.at(i.size() - 1)) {
|
||||
std::vector<int_pair>::iterator tit = coordinates.begin();
|
||||
i.insert(i.end(), ++tit, coordinates.end());
|
||||
remove = true;
|
||||
coordinates = i;
|
||||
} else if (coordinates.at(coordinates.size() - 1) == i.at(0)) {
|
||||
std::vector<int_pair>::iterator tit = i.begin();
|
||||
coordinates.insert(coordinates.end(), ++tit, i.end());
|
||||
remove = true;
|
||||
}
|
||||
if (remove) {
|
||||
std::vector<std::vector<int_pair> >::iterator ti = incompletedRings.begin();
|
||||
ti += k;
|
||||
incompletedRings.erase(ti);
|
||||
} else {
|
||||
k++;
|
||||
}
|
||||
if (coordinates.at(0) == coordinates.at(coordinates.size() - 1)) {
|
||||
completedRings.push_back(coordinates);
|
||||
add = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (add) {
|
||||
incompletedRings.push_back(coordinates);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int safelyAddDelta(int number, int delta) {
|
||||
int res = number + delta;
|
||||
if (delta > 0 && res < number) {
|
||||
return INT_MAX;
|
||||
} else if (delta < 0 && res > number) {
|
||||
return INT_MIN;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void unifyIncompletedRings(std::vector<std::vector<int_pair> >& toProccess, std::vector<std::vector<int_pair> >& completedRings,
|
||||
int leftX, int rightX, int bottomY, int topY, long dbId, int zoom) {
|
||||
std::set<int> nonvisitedRings;
|
||||
std::vector<coordinates > incompletedRings(toProccess);
|
||||
toProccess.clear();
|
||||
std::vector<coordinates >::iterator ir = incompletedRings.begin();
|
||||
int j = 0;
|
||||
for (j = 0; ir != incompletedRings.end(); ir++,j++) {
|
||||
int x = ir->at(0).first;
|
||||
int y = ir->at(0).second;
|
||||
int sx = ir->at(ir->size() - 1).first;
|
||||
int sy = ir->at(ir->size() - 1).second;
|
||||
bool st = y == topY || x == rightX || y == bottomY || x == leftX;
|
||||
bool end = sy == topY || sx == rightX || sy == bottomY || sx == leftX;
|
||||
// something goes wrong
|
||||
// These exceptions are used to check logic about processing multipolygons
|
||||
// However this situation could happen because of broken multipolygons (so it should data causes app error)
|
||||
// that's why these exceptions could be replaced with return; statement.
|
||||
if (!end || !st) {
|
||||
osmand_log_print(LOG_ERROR, "Error processing multipolygon");
|
||||
toProccess.push_back(*ir);
|
||||
} else {
|
||||
nonvisitedRings.insert(j);
|
||||
}
|
||||
}
|
||||
ir = incompletedRings.begin();
|
||||
for (j = 0; ir != incompletedRings.end(); ir++, j++) {
|
||||
if (nonvisitedRings.find(j) == nonvisitedRings.end()) {
|
||||
continue;
|
||||
}
|
||||
int x = ir->at(ir->size() - 1).first;
|
||||
int y = ir->at(ir->size() - 1).second;
|
||||
// 31 - (zoom + 8)
|
||||
const int EVAL_DELTA = 6 << (23 - zoom);
|
||||
const int UNDEFINED_MIN_DIFF = -1 - EVAL_DELTA;
|
||||
while (true) {
|
||||
int st = 0; // st already checked to be one of the four
|
||||
if (y == topY) {
|
||||
st = 0;
|
||||
} else if (x == rightX) {
|
||||
st = 1;
|
||||
} else if (y == bottomY) {
|
||||
st = 2;
|
||||
} else if (x == leftX) {
|
||||
st = 3;
|
||||
}
|
||||
int nextRingIndex = -1;
|
||||
// BEGIN go clockwise around rectangle
|
||||
for (int h = st; h < st + 4; h++) {
|
||||
|
||||
// BEGIN find closest nonvisited start (including current)
|
||||
int mindiff = UNDEFINED_MIN_DIFF;
|
||||
std::vector<std::vector<int_pair> >::iterator cni = incompletedRings.begin();
|
||||
int cnik = 0;
|
||||
for (;cni != incompletedRings.end(); cni++, cnik ++) {
|
||||
if (nonvisitedRings.find(cnik) == nonvisitedRings.end()) {
|
||||
continue;
|
||||
}
|
||||
int csx = cni->at(0).first;
|
||||
int csy = cni->at(0).second;
|
||||
if (h % 4 == 0) {
|
||||
// top
|
||||
if (csy == topY && csx >= safelyAddDelta(x, -EVAL_DELTA)) {
|
||||
if (mindiff == UNDEFINED_MIN_DIFF || (csx - x) <= mindiff) {
|
||||
mindiff = (csx - x);
|
||||
nextRingIndex = cnik;
|
||||
}
|
||||
}
|
||||
} else if (h % 4 == 1) {
|
||||
// right
|
||||
if (csx == rightX && csy >= safelyAddDelta(y, -EVAL_DELTA)) {
|
||||
if (mindiff == UNDEFINED_MIN_DIFF || (csy - y) <= mindiff) {
|
||||
mindiff = (csy - y);
|
||||
nextRingIndex = cnik;
|
||||
}
|
||||
}
|
||||
} else if (h % 4 == 2) {
|
||||
// bottom
|
||||
if (csy == bottomY && csx <= safelyAddDelta(x, EVAL_DELTA)) {
|
||||
if (mindiff == UNDEFINED_MIN_DIFF || (x - csx) <= mindiff) {
|
||||
mindiff = (x - csx);
|
||||
nextRingIndex = cnik;
|
||||
}
|
||||
}
|
||||
} else if (h % 4 == 3) {
|
||||
// left
|
||||
if (csx == leftX && csy <= safelyAddDelta(y, EVAL_DELTA)) {
|
||||
if (mindiff == UNDEFINED_MIN_DIFF || (y - csy) <= mindiff) {
|
||||
mindiff = (y - csy);
|
||||
nextRingIndex = cnik;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // END find closest start (including current)
|
||||
|
||||
// we found start point
|
||||
if (mindiff != UNDEFINED_MIN_DIFF) {
|
||||
break;
|
||||
} else {
|
||||
if (h % 4 == 0) {
|
||||
// top
|
||||
y = topY;
|
||||
x = rightX;
|
||||
} else if (h % 4 == 1) {
|
||||
// right
|
||||
y = bottomY;
|
||||
x = rightX;
|
||||
} else if (h % 4 == 2) {
|
||||
// bottom
|
||||
y = bottomY;
|
||||
x = leftX;
|
||||
} else if (h % 4 == 3) {
|
||||
y = topY;
|
||||
x = leftX;
|
||||
}
|
||||
ir->push_back(int_pair(x, y));
|
||||
}
|
||||
|
||||
} // END go clockwise around rectangle
|
||||
if (nextRingIndex == -1) {
|
||||
// it is impossible (current start should always be found)
|
||||
} else if (nextRingIndex == j) {
|
||||
ir->push_back(ir->at(0));
|
||||
nonvisitedRings.erase(j);
|
||||
break;
|
||||
} else {
|
||||
std::vector<int_pair> p = incompletedRings.at(nextRingIndex);
|
||||
ir->insert(ir->end(), p.begin(), p.end());
|
||||
nonvisitedRings.erase(nextRingIndex);
|
||||
// get last point and start again going clockwise
|
||||
x = ir->at(ir->size() - 1).first;
|
||||
y = ir->at(ir->size() - 1).second;
|
||||
}
|
||||
}
|
||||
|
||||
completedRings.push_back(*ir);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return -1 if there is no instersection or x<<32 | y
|
||||
*/
|
||||
bool calculateIntersection(int x, int y, int px, int py, int leftX, int rightX, int bottomY, int topY, int_pair& b) {
|
||||
// firstly try to search if the line goes in
|
||||
if (py < topY && y >= topY) {
|
||||
int tx = (int) (px + ((double) (x - px) * (topY - py)) / (y - py));
|
||||
if (leftX <= tx && tx <= rightX) {
|
||||
b.first = tx;
|
||||
b.second = topY;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (py > bottomY && y <= bottomY) {
|
||||
int tx = (int) (px + ((double) (x - px) * (py - bottomY)) / (py - y));
|
||||
if (leftX <= tx && tx <= rightX) {
|
||||
b.first = tx;
|
||||
b.second = bottomY;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (px < leftX && x >= leftX) {
|
||||
int ty = (int) (py + ((double) (y - py) * (leftX - px)) / (x - px));
|
||||
if (ty >= topY && ty <= bottomY) {
|
||||
b.first = leftX;
|
||||
b.second = ty;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
if (px > rightX && x <= rightX) {
|
||||
int ty = (int) (py + ((double) (y - py) * (px - rightX)) / (px - x));
|
||||
if (ty >= topY && ty <= bottomY) {
|
||||
b.first = rightX;
|
||||
b.second = ty;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// try to search if point goes out
|
||||
if (py > topY && y <= topY) {
|
||||
int tx = (int) (px + ((double) (x - px) * (topY - py)) / (y - py));
|
||||
if (leftX <= tx && tx <= rightX) {
|
||||
b.first = tx;
|
||||
b.second = topY;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (py < bottomY && y >= bottomY) {
|
||||
int tx = (int) (px + ((double) (x - px) * (py - bottomY)) / (py - y));
|
||||
if (leftX <= tx && tx <= rightX) {
|
||||
b.first = tx;
|
||||
b.second = bottomY;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (px > leftX && x <= leftX) {
|
||||
int ty = (int) (py + ((double) (y - py) * (leftX - px)) / (x - px));
|
||||
if (ty >= topY && ty <= bottomY) {
|
||||
b.first = leftX;
|
||||
b.second = ty;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
if (px < rightX && x >= rightX) {
|
||||
int ty = (int) (py + ((double) (y - py) * (px - rightX)) / (px - x));
|
||||
if (ty >= topY && ty <= bottomY) {
|
||||
b.first = rightX;
|
||||
b.second = ty;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (px == rightX || px == leftX || py == topY || py == bottomY) {
|
||||
b.first = px;
|
||||
b.second = py;
|
||||
// return true;
|
||||
// Is it right? to not return anything?
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool calculateLineCoordinates(bool inside, int x, int y, bool pinside, int px, int py, int leftX, int rightX,
|
||||
int bottomY, int topY, std::vector<int_pair>& coordinates) {
|
||||
bool lineEnded = false;
|
||||
int_pair b(x, y);
|
||||
if (pinside) {
|
||||
if (!inside) {
|
||||
bool is = calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY, b);
|
||||
if (!is) {
|
||||
b.first = px;
|
||||
b.second = py;
|
||||
}
|
||||
coordinates.push_back(b);
|
||||
lineEnded = true;
|
||||
} else {
|
||||
coordinates.push_back(b);
|
||||
}
|
||||
} else {
|
||||
bool is = calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY, b);
|
||||
if (inside) {
|
||||
// assert is != -1;
|
||||
coordinates.push_back(b);
|
||||
int_pair n(x, y);
|
||||
coordinates.push_back(n);
|
||||
} else if (is) {
|
||||
coordinates.push_back(b);
|
||||
calculateIntersection(x, y, b.first, b.second, leftX, rightX, bottomY, topY, b);
|
||||
coordinates.push_back(b);
|
||||
lineEnded = true;
|
||||
}
|
||||
}
|
||||
|
||||
return lineEnded;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef _MULTIPOLYGONS_H
|
||||
#define _MULTIPOLYGONS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "renderRules.h"
|
||||
#include "common.h"
|
||||
#include "mapObjects.h"
|
||||
|
||||
/// !!! Fuly copied from MapRenderRepositories.java, should be carefully synchroinized
|
||||
bool isClockwiseWay(std::vector<int_pair>& c) ;
|
||||
|
||||
bool calculateLineCoordinates(bool inside, int x, int y, bool pinside, int px, int py, int leftX, int rightX,
|
||||
int bottomY, int topY, std::vector<int_pair>& coordinates);
|
||||
|
||||
void combineMultipolygonLine(std::vector<coordinates>& completedRings, std::vector<coordinates>& incompletedRings,
|
||||
coordinates& coordinates);
|
||||
|
||||
void unifyIncompletedRings(std::vector<std::vector<int_pair> >& incompletedRings, std::vector<std::vector<int_pair> >& completedRings,
|
||||
int leftX, int rightX, int bottomY, int topY, long dbId, int zoom);
|
||||
|
||||
|
||||
bool processCoastlines(std::vector<MapDataObject*>& coastLines, int leftX, int rightX, int bottomY, int topY, int zoom,
|
||||
bool showIfThereIncompleted, bool addDebugIncompleted, std::vector<MapDataObject*>& res);
|
||||
|
||||
#endif
|
|
@ -1,52 +0,0 @@
|
|||
#ifndef _OSMAND_LOG_CPP
|
||||
#define _OSMAND_LOG_CPP
|
||||
#include "osmand_log.h"
|
||||
|
||||
|
||||
#ifdef ANDROID_BUILD
|
||||
#include <android/log.h>
|
||||
|
||||
const char* const LOG_TAG = "net.osmand:native";
|
||||
void osmand_log_print(int type, const char* msg, ...) {
|
||||
va_list args;
|
||||
va_start( args, msg);
|
||||
if(type == LOG_ERROR) {
|
||||
__android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, msg, args);
|
||||
} else if(type == LOG_INFO) {
|
||||
__android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, msg, args);
|
||||
} else if(type == LOG_WARN) {
|
||||
__android_log_vprint(ANDROID_LOG_WARN, LOG_TAG, msg, args);
|
||||
} else {
|
||||
__android_log_vprint(ANDROID_LOG_DEBUG, LOG_TAG, msg, args);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
const char* const LOG_TAG = "net.osmand:native";
|
||||
void osmand_log_print(int type, const char* msg, ...) {
|
||||
va_list args;
|
||||
va_start( args, msg);
|
||||
if(type == LOG_ERROR) {
|
||||
printf("ERROR: ");
|
||||
} else if(type == LOG_INFO) {
|
||||
printf("INFO: ");
|
||||
} else if(type == LOG_WARN) {
|
||||
printf("WARN: ");
|
||||
} else {
|
||||
printf("DEBUG: ");
|
||||
}
|
||||
vprintf(msg, args);
|
||||
printf("\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef _OSMAND_LOG_H
|
||||
#define _OSMAND_LOG_H
|
||||
|
||||
typedef enum osmand_LogPriority {
|
||||
LOG_ERROR = 1,
|
||||
LOG_WARN,
|
||||
LOG_DEBUG,
|
||||
LOG_INFO
|
||||
} osmand_LogPriority;
|
||||
//#define _ANDROID_BUILD
|
||||
void osmand_log_print(int type, const char* msg, ...);
|
||||
|
||||
|
||||
#endif
|
|
@ -1,333 +0,0 @@
|
|||
#include "binaryRead.h"
|
||||
#include "renderRules.h"
|
||||
#include "rendering.h"
|
||||
#include <SkImageEncoder.h>
|
||||
#include <SkGraphics.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
void println(const char * msg) {
|
||||
printf("%s\n", msg);
|
||||
}
|
||||
|
||||
void printUsage(std::string info) {
|
||||
if(info.size() > 0) {
|
||||
println(info.c_str());
|
||||
}
|
||||
println("Inspector is console utility for working with binary indexes of OsmAnd.");
|
||||
println("It allows print info about file, extract parts and merge indexes.");
|
||||
println("\nUsage for print info : inspector [-renderingOutputFile=..] [-vaddress] [-vmap] [-vpoi] [-vtransport] [-zoom=Zoom] [-bbox=LeftLon,TopLat,RightLon,BottomLan] [file]");
|
||||
println(" Prints information about [file] binary index of OsmAnd.");
|
||||
println(" -v.. more verbouse output (like all cities and their streets or all map objects with tags/values and coordinates)");
|
||||
println(" -renderingOutputFile= renders for specified zoom, bbox into a file");
|
||||
}
|
||||
|
||||
class RenderingInfo {
|
||||
public:
|
||||
int left, right, top, bottom;
|
||||
double lattop, lonleft;
|
||||
int tileWX, tileHY;
|
||||
std::string tileFileName;
|
||||
std::string renderingFileName;
|
||||
std::string imagesFileName;
|
||||
int zoom;
|
||||
int width ;
|
||||
int height;
|
||||
|
||||
RenderingInfo(int argc, char **params) {
|
||||
double l1, l2;
|
||||
char s[100];
|
||||
int z, z1, z2 ;
|
||||
lattop = 85;
|
||||
tileHY = 2;
|
||||
lonleft = -180;
|
||||
tileWX = 2;
|
||||
zoom = 15;
|
||||
for (int i = 1; i != argc; ++i) {
|
||||
if (sscanf(params[i], "-renderingOutputFile=%s", s)) {
|
||||
tileFileName = s;
|
||||
} else if (sscanf(params[i], "-imagesBasePathFile=%s", s)) {
|
||||
imagesFileName = s;
|
||||
} else if (sscanf(params[i], "-renderingStyleFile=%s", s)) {
|
||||
renderingFileName = s;
|
||||
} else if (sscanf(params[i], "-zoom=%d", &z)) {
|
||||
zoom = z;
|
||||
} else if (sscanf(params[i], "-lbox=%lg,%lg", &l1, &l2)) {
|
||||
lonleft = l1;
|
||||
lattop = l2;
|
||||
} else if (sscanf(params[i], "-lt=%d,%d", &z1, &z2)) {
|
||||
tileWX = z1;
|
||||
tileHY = z2;
|
||||
}
|
||||
}
|
||||
|
||||
left = get31TileNumberX(lonleft);
|
||||
top = get31TileNumberY(lattop);
|
||||
right = left + tileWX * (1 << (31 - zoom));
|
||||
bottom = top + tileHY * (1 << (31 - zoom));
|
||||
width = tileWX * TILE_SIZE;
|
||||
height = tileHY * TILE_SIZE;
|
||||
}
|
||||
};
|
||||
|
||||
class VerboseInfo {
|
||||
public:
|
||||
bool vaddress;
|
||||
bool vtransport;
|
||||
bool vpoi;
|
||||
bool vmap;
|
||||
double lattop, latbottom, lonleft, lonright;
|
||||
int zoom;
|
||||
|
||||
VerboseInfo(int argc, char **params) {
|
||||
lattop = 85;
|
||||
latbottom = -85;
|
||||
lonleft = -180;
|
||||
lonright = 180;
|
||||
zoom = 15;
|
||||
int z;
|
||||
double l1, l2, l3, l4;
|
||||
for (int i = 1; i != argc; ++i) {
|
||||
if (strcmp(params[i], "-vaddress") == 0) {
|
||||
vaddress = true;
|
||||
} else if (strcmp(params[i], "-vmap") == 0) {
|
||||
vmap = true;
|
||||
} else if (strcmp(params[i], "-vpoi") == 0) {
|
||||
vpoi = true;
|
||||
} else if (strcmp(params[i], "-vtransport") == 0) {
|
||||
vtransport = true;
|
||||
} else if (sscanf(params[i], "-zoom=%d", &z)) {
|
||||
zoom = z;
|
||||
} else if (sscanf(params[i], "-bbox=%le,%le,%le,%le", &l1, &l2, &l3, &l4)) {
|
||||
lonleft = l1;
|
||||
lattop = l2;
|
||||
lonright = l3;
|
||||
latbottom = l4;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// public boolean contains(MapObject o){
|
||||
// return lattop >= o.getLocation().getLatitude() && latbottom <= o.getLocation().getLatitude()
|
||||
// && lonleft <= o.getLocation().getLongitude() && lonright >= o.getLocation().getLongitude();
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
const char* formatBounds(int left, int right, int top, int bottom){
|
||||
float l = get31LongitudeX(left);
|
||||
float r = get31LongitudeX(right);
|
||||
float t = get31LatitudeY(top);
|
||||
float b = get31LatitudeY(bottom);
|
||||
char* ch = new char[150];
|
||||
sprintf(ch, "(left top - right bottom) : %g, %g NE - %g, %g NE", l, t,r, b);
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
void printFileInformation(const char* fileName, VerboseInfo* verbose) {
|
||||
BinaryMapFile* file = initBinaryMapFile(fileName);
|
||||
std::vector<BinaryPartIndex*>::iterator its = file->indexes.begin();
|
||||
time_t date = file->dateCreated/1000;
|
||||
printf("Obf file.\n Version %d, basemap %d, date %s \n", file->version,
|
||||
file->basemap, ctime(&date));
|
||||
|
||||
int i = 1;
|
||||
for (; its != file->indexes.end(); its++, i++) {
|
||||
BinaryPartIndex* it = *its;
|
||||
std::string partname = "";
|
||||
if (it->type == MAP_INDEX) {
|
||||
partname = "Map";
|
||||
} else if (it->type == TRANSPORT_INDEX) {
|
||||
partname = "Transport";
|
||||
} else if (it->type == ROUTING_INDEX) {
|
||||
partname = "Routing";
|
||||
} else if (it->type == POI_INDEX) {
|
||||
partname = "Poi";
|
||||
} else if (it->type == ADDRESS_INDEX) {
|
||||
partname = "Address";
|
||||
}
|
||||
printf("%d. %s data %s - %d bytes\n", i, partname.c_str(), it->name.c_str(), it->length);
|
||||
if (it->type == MAP_INDEX) {
|
||||
MapIndex* m = ((MapIndex*) it);
|
||||
int j = 1;
|
||||
std::vector<MapRoot>::iterator rt = m->levels.begin();
|
||||
for (; rt != m->levels.end(); rt++) {
|
||||
const char* ch = formatBounds(rt->left, rt->right, rt->top, rt->bottom);
|
||||
printf("\t%d.%d Map level minZoom = %d, maxZoom = %d, size = %d bytes \n\t\t Bounds %s \n",
|
||||
i, j++, rt->minZoom, rt->maxZoom, rt->length, ch);
|
||||
}
|
||||
if ((verbose != NULL && verbose->vmap)) {
|
||||
//printMapDetailInfo(verbose, index);
|
||||
}
|
||||
} else if (it->type == TRANSPORT_INDEX) {
|
||||
// TransportIndex ti = ((TransportIndex) p);
|
||||
// int sh = (31 - BinaryMapIndexReader.TRANSPORT_STOP_ZOOM);
|
||||
// println(
|
||||
// "\t Bounds "
|
||||
// + formatBounds(ti.getLeft() << sh, ti.getRight() << sh, ti.getTop() << sh,
|
||||
// ti.getBottom() << sh));
|
||||
} else if (it->type == POI_INDEX && (verbose != NULL && verbose->vpoi)) {
|
||||
//printPOIDetailInfo(verbose, index, (PoiRegion) p);
|
||||
} else if (it->type == ADDRESS_INDEX && (verbose != NULL && verbose->vaddress)) {
|
||||
// printAddressDetailedInfo(verbose, index);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void runSimpleRendering( string renderingFileName, string resourceDir, RenderingInfo* info) {
|
||||
SkColor defaultMapColor = SK_ColorLTGRAY;
|
||||
|
||||
if (info->width > 10000 || info->height > 10000) {
|
||||
osmand_log_print(LOG_ERROR, "We don't rendering images more than 10000x10000 ");
|
||||
return;
|
||||
}
|
||||
|
||||
osmand_log_print(LOG_INFO, "Rendering info bounds(%d, %d, %d, %d) zoom(%d), width/height(%d/%d) tilewidth/tileheight(%d/%d) fileName(%s)",
|
||||
info->left, info->top, info->right, info->bottom, info->zoom, info->width, info->height, info->tileWX, info->tileHY, info->tileFileName.c_str());
|
||||
RenderingRulesStorage* st = new RenderingRulesStorage(renderingFileName.c_str());
|
||||
st->parseRulesFromXmlInputStream(renderingFileName.c_str(), NULL);
|
||||
RenderingRuleSearchRequest* searchRequest = new RenderingRuleSearchRequest(st);
|
||||
ResultPublisher* publisher = new ResultPublisher();
|
||||
SearchQuery q(floor(info->left), floor(info->right), ceil(info->top), ceil(info->bottom), searchRequest, publisher);
|
||||
q.zoom = info->zoom;
|
||||
|
||||
ResultPublisher* res = searchObjectsForRendering(&q, true, "Nothing found");
|
||||
osmand_log_print(LOG_INFO, "Found %d objects", res->result.size());
|
||||
|
||||
SkBitmap* bitmap = new SkBitmap();
|
||||
bitmap->setConfig(SkBitmap::kRGB_565_Config, info->width, info->height);
|
||||
|
||||
size_t bitmapDataSize = bitmap->getSize();
|
||||
void* bitmapData = malloc(bitmapDataSize);
|
||||
bitmap->setPixels(bitmapData);
|
||||
|
||||
osmand_log_print(LOG_INFO, "Initializing rendering style and rendering context");
|
||||
ElapsedTimer initObjects;
|
||||
initObjects.start();
|
||||
|
||||
RenderingContext rc;
|
||||
rc.setDefaultIconsDir(resourceDir);
|
||||
searchRequest->clearState();
|
||||
searchRequest->setIntFilter(st->PROPS.R_MINZOOM, info->zoom);
|
||||
if (searchRequest->searchRenderingAttribute(A_DEFAULT_COLOR)) {
|
||||
defaultMapColor = searchRequest->getIntPropertyValue(searchRequest->props()->R_ATTR_COLOR_VALUE);
|
||||
}
|
||||
searchRequest->clearState();
|
||||
searchRequest->setIntFilter(st->PROPS.R_MINZOOM, info->zoom);
|
||||
if (searchRequest->searchRenderingAttribute(A_SHADOW_RENDERING)) {
|
||||
rc.setShadowRenderingMode(searchRequest->getIntPropertyValue(searchRequest->props()->R_ATTR_INT_VALUE));
|
||||
//rc.setShadowRenderingColor(searchRequest->getIntPropertyValue(searchRequest->props()->R_SHADOW_COLOR));
|
||||
}
|
||||
rc.setLocation(
|
||||
((double)info->left)/getPowZoom(31-info->zoom),
|
||||
((double)info->top)/getPowZoom(31-info->zoom)
|
||||
);
|
||||
rc.setDimension(info->width, info->height);
|
||||
rc.setZoom(info->zoom);
|
||||
rc.setRotate(0);
|
||||
rc.setDensityScale(1);
|
||||
osmand_log_print(LOG_INFO, "Rendering image");
|
||||
initObjects.pause();
|
||||
SkCanvas* canvas = new SkCanvas(*bitmap);
|
||||
canvas->drawColor(defaultMapColor);
|
||||
doRendering(res->result, canvas, searchRequest, &rc);
|
||||
osmand_log_print(LOG_INFO, "End Rendering image");
|
||||
osmand_log_print(LOG_INFO, "Native ok (init %d, rendering %d) ", initObjects.getElapsedTime(),
|
||||
rc.nativeOperations.getElapsedTime());
|
||||
SkImageEncoder* enc = SkImageEncoder::Create(SkImageEncoder::kPNG_Type);
|
||||
if (enc != NULL && !enc->encodeFile(info->tileFileName.c_str(), *bitmap, 100)) {
|
||||
osmand_log_print(LOG_ERROR, "FAIL to save tile to %s", info->tileFileName.c_str());
|
||||
} else {
|
||||
osmand_log_print(LOG_INFO, "Tile successfully saved to %s", info->tileFileName.c_str());
|
||||
}
|
||||
delete enc;
|
||||
delete publisher;
|
||||
delete searchRequest;
|
||||
delete st;
|
||||
delete canvas;
|
||||
delete bitmap;
|
||||
free(bitmapData);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void testRenderingRuleStorage(const char* basePath, const char* name) {
|
||||
string filePath = string(basePath) + string(name);
|
||||
RenderingRulesStorage* st = new RenderingRulesStorage(filePath.c_str());
|
||||
st->parseRulesFromXmlInputStream(filePath.c_str(),
|
||||
new BasePathRenderingRulesStorageResolver(string(basePath)));
|
||||
st->printDebug(RenderingRulesStorage::TEXT_RULES);
|
||||
RenderingRuleSearchRequest* searchRequest = new RenderingRuleSearchRequest(st);
|
||||
searchRequest->setStringFilter(st->PROPS.R_TAG, "highway");
|
||||
searchRequest->setStringFilter(st->PROPS.R_VALUE, "motorway");
|
||||
searchRequest->setIntFilter(st->PROPS.R_LAYER, 1);
|
||||
searchRequest->setIntFilter(st->PROPS.R_MINZOOM, 15);
|
||||
searchRequest->setIntFilter(st->PROPS.R_MAXZOOM, 15);
|
||||
// searchRequest.setBooleanFilter(storage.PROPS.R_NIGHT_MODE, true);
|
||||
// searchRequest.setBooleanFilter(storage.PROPS.get("hmRendered"), true);
|
||||
|
||||
bool res = searchRequest->search(RenderingRulesStorage::LINE_RULES, true);
|
||||
printf("Result %d\n", res);
|
||||
searchRequest->printDebugResult();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc <= 1) {
|
||||
// 1. Test Rendering rule storage
|
||||
// testRenderingRuleStorage("/home/victor/projects/OsmAnd/git/DataExtractionOSM/src/net/osmand/render/",
|
||||
// "test_depends.render.xml"
|
||||
// "default.render.xml"
|
||||
// );
|
||||
// 2. Test simple rendering
|
||||
printUsage("");
|
||||
return 1;
|
||||
}
|
||||
const char* f = argv[1];
|
||||
if (f[0] == '-') {
|
||||
// command
|
||||
if (f[1]=='v') {
|
||||
if (argc < 2) {
|
||||
printUsage("Missing file parameter");
|
||||
} else {
|
||||
VerboseInfo* vinfo = new VerboseInfo(argc, argv);
|
||||
printFileInformation(argv[argc -1], vinfo);
|
||||
}
|
||||
} else if (f[1]=='r') {
|
||||
if (argc < 2) {
|
||||
printUsage("Missing file parameter");
|
||||
} else {
|
||||
RenderingInfo* info = new RenderingInfo(argc, argv);
|
||||
char s[100];
|
||||
for (int i = 1; i != argc; ++i) {
|
||||
if (sscanf(argv[i], "-renderingInputFile=%s", s)) {
|
||||
BinaryMapFile* mf = initBinaryMapFile(s);
|
||||
osmand_log_print(LOG_INFO, "Init %d (success) binary map file %s.", mf->version,
|
||||
mf->inputName.c_str());
|
||||
}
|
||||
}
|
||||
runSimpleRendering(info->renderingFileName, info->imagesFileName, info);
|
||||
for (int i = 1; i != argc; ++i) {
|
||||
if (sscanf(argv[i], "-renderingInputFile=%s", s)) {
|
||||
closeBinaryMapFile(s);
|
||||
}
|
||||
}
|
||||
delete info;
|
||||
}
|
||||
} else {
|
||||
printUsage("Unknown command");
|
||||
}
|
||||
} else {
|
||||
printFileInformation(f, NULL);
|
||||
}
|
||||
|
||||
SkGraphics::PurgeFontCache();
|
||||
purgeCachedBitmaps();
|
||||
}
|
|
@ -1,266 +0,0 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <ppapi/cpp/completion_callback.h>
|
||||
#include <ppapi/cpp/var.h>
|
||||
#include <ppapi/cpp/module.h>
|
||||
|
||||
#include "osmand_nacl.h"
|
||||
|
||||
namespace {
|
||||
const int kPthreadMutexSuccess = 0;
|
||||
const char* const kPaintMethodId = "paint";
|
||||
const double kInvalidPiValue = -1.0;
|
||||
const int kMaxPointCount = 1000000000; // The total number of points to draw.
|
||||
const uint32_t kOpaqueColorMask = 0xff000000; // Opaque pixels.
|
||||
const uint32_t kRedMask = 0xff0000;
|
||||
const uint32_t kBlueMask = 0xff;
|
||||
const uint32_t kRedShift = 16;
|
||||
const uint32_t kBlueShift = 0;
|
||||
|
||||
// This is called by the browser when the 2D context has been flushed to the
|
||||
// browser window.
|
||||
void FlushCallback(void* data, int32_t result) {
|
||||
static_cast<osmand::PiGenerator*>(data)->set_flush_pending(false);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace osmand {
|
||||
|
||||
// A small helper RAII class that implementes a scoped pthread_mutex lock.
|
||||
class ScopedMutexLock {
|
||||
public:
|
||||
explicit ScopedMutexLock(pthread_mutex_t* mutex) : mutex_(mutex) {
|
||||
if (pthread_mutex_lock(mutex_) != kPthreadMutexSuccess) {
|
||||
mutex_ = NULL;
|
||||
}
|
||||
}
|
||||
~ScopedMutexLock() {
|
||||
if (mutex_)
|
||||
pthread_mutex_unlock(mutex_);
|
||||
}
|
||||
bool is_valid() const {
|
||||
return mutex_ != NULL;
|
||||
}
|
||||
private:
|
||||
pthread_mutex_t* mutex_; // Weak reference.
|
||||
};
|
||||
|
||||
// A small helper RAII class used to acquire and release the pixel lock.
|
||||
class ScopedPixelLock {
|
||||
public:
|
||||
explicit ScopedPixelLock(PiGenerator* image_owner)
|
||||
: image_owner_(image_owner), pixels_(image_owner->LockPixels()) {}
|
||||
|
||||
~ScopedPixelLock() {
|
||||
pixels_ = NULL;
|
||||
image_owner_->UnlockPixels();
|
||||
}
|
||||
|
||||
uint32_t* pixels() const {
|
||||
return pixels_;
|
||||
}
|
||||
private:
|
||||
PiGenerator* image_owner_; // Weak reference.
|
||||
uint32_t* pixels_; // Weak reference.
|
||||
|
||||
ScopedPixelLock(); // Not implemented, do not use.
|
||||
};
|
||||
|
||||
PiGenerator::PiGenerator(PP_Instance instance)
|
||||
: pp::Instance(instance),
|
||||
graphics_2d_context_(NULL),
|
||||
pixel_buffer_(NULL),
|
||||
flush_pending_(false),
|
||||
quit_(false),
|
||||
compute_pi_thread_(0),
|
||||
pi_(0.0) {
|
||||
pthread_mutex_init(&pixel_buffer_mutex_, NULL);
|
||||
}
|
||||
|
||||
PiGenerator::~PiGenerator() {
|
||||
quit_ = true;
|
||||
if (compute_pi_thread_) {
|
||||
pthread_join(compute_pi_thread_, NULL);
|
||||
}
|
||||
DestroyContext();
|
||||
// The ComputePi() thread should be gone by now, so there is no need to
|
||||
// acquire the mutex for |pixel_buffer_|.
|
||||
delete pixel_buffer_;
|
||||
pthread_mutex_destroy(&pixel_buffer_mutex_);
|
||||
}
|
||||
|
||||
void PiGenerator::DidChangeView(const pp::Rect& position,
|
||||
const pp::Rect& clip) {
|
||||
if (position.size().width() == width() &&
|
||||
position.size().height() == height())
|
||||
return; // Size didn't change, no need to update anything.
|
||||
|
||||
// Create a new device context with the new size.
|
||||
DestroyContext();
|
||||
CreateContext(position.size());
|
||||
// Delete the old pixel buffer and create a new one.
|
||||
ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
|
||||
delete pixel_buffer_;
|
||||
pixel_buffer_ = NULL;
|
||||
if (graphics_2d_context_ != NULL) {
|
||||
pixel_buffer_ = new pp::ImageData(this,
|
||||
PP_IMAGEDATAFORMAT_BGRA_PREMUL,
|
||||
graphics_2d_context_->size(),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
bool PiGenerator::Init(uint32_t argc, const char* argn[], const char* argv[]) {
|
||||
pthread_create(&compute_pi_thread_, NULL, ComputePi, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t* PiGenerator::LockPixels() {
|
||||
void* pixels = NULL;
|
||||
// Do not use a ScopedMutexLock here, since the lock needs to be held until
|
||||
// the matching UnlockPixels() call.
|
||||
if (pthread_mutex_lock(&pixel_buffer_mutex_) == kPthreadMutexSuccess) {
|
||||
if (pixel_buffer_ != NULL && !pixel_buffer_->is_null()) {
|
||||
pixels = pixel_buffer_->data();
|
||||
}
|
||||
}
|
||||
return reinterpret_cast<uint32_t*>(pixels);
|
||||
}
|
||||
|
||||
void PiGenerator::HandleMessage(const pp::Var& var_message) {
|
||||
if (!var_message.is_string()) {
|
||||
PostMessage(pp::Var(kInvalidPiValue));
|
||||
}
|
||||
std::string message = var_message.AsString();
|
||||
if (message == kPaintMethodId) {
|
||||
Paint();
|
||||
} else {
|
||||
PostMessage(pp::Var(kInvalidPiValue));
|
||||
}
|
||||
}
|
||||
|
||||
void PiGenerator::UnlockPixels() const {
|
||||
pthread_mutex_unlock(&pixel_buffer_mutex_);
|
||||
}
|
||||
|
||||
void PiGenerator::Paint() {
|
||||
ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
|
||||
if (!scoped_mutex.is_valid()) {
|
||||
return;
|
||||
}
|
||||
FlushPixelBuffer();
|
||||
// Post the current estimate of Pi back to the browser.
|
||||
pp::Var pi_estimate(pi());
|
||||
// Paint() is called on the main thread, so no need for CallOnMainThread()
|
||||
// here. It's OK to just post the message.
|
||||
PostMessage(pi_estimate);
|
||||
}
|
||||
|
||||
void PiGenerator::CreateContext(const pp::Size& size) {
|
||||
ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
|
||||
if (!scoped_mutex.is_valid()) {
|
||||
return;
|
||||
}
|
||||
if (IsContextValid())
|
||||
return;
|
||||
graphics_2d_context_ = new pp::Graphics2D(this, size, false);
|
||||
if (!BindGraphics(*graphics_2d_context_)) {
|
||||
printf("Couldn't bind the device context\n");
|
||||
}
|
||||
}
|
||||
|
||||
void PiGenerator::DestroyContext() {
|
||||
ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
|
||||
if (!scoped_mutex.is_valid()) {
|
||||
return;
|
||||
}
|
||||
if (!IsContextValid())
|
||||
return;
|
||||
delete graphics_2d_context_;
|
||||
graphics_2d_context_ = NULL;
|
||||
}
|
||||
|
||||
void PiGenerator::FlushPixelBuffer() {
|
||||
if (!IsContextValid())
|
||||
return;
|
||||
// Note that the pixel lock is held while the buffer is copied into the
|
||||
// device context and then flushed.
|
||||
graphics_2d_context_->PaintImageData(*pixel_buffer_, pp::Point());
|
||||
if (flush_pending())
|
||||
return;
|
||||
set_flush_pending(true);
|
||||
graphics_2d_context_->Flush(pp::CompletionCallback(&FlushCallback, this));
|
||||
}
|
||||
|
||||
void* PiGenerator::ComputePi(void* param) {
|
||||
int count = 0; // The number of points put inside the inscribed quadrant.
|
||||
unsigned int seed = 1;
|
||||
PiGenerator* pi_generator = static_cast<PiGenerator*>(param);
|
||||
srand(seed);
|
||||
for (int i = 1; i <= kMaxPointCount && !pi_generator->quit(); ++i) {
|
||||
ScopedPixelLock scoped_pixel_lock(pi_generator);
|
||||
uint32_t* pixel_bits = scoped_pixel_lock.pixels();
|
||||
if (pixel_bits == NULL) {
|
||||
// Note that if the pixel buffer never gets initialized, this won't ever
|
||||
// paint anything. Which is probably the right thing to do. Also, this
|
||||
// clause means that the image will not get the very first few Pi dots,
|
||||
// since it's possible that this thread starts before the pixel buffer is
|
||||
// initialized.
|
||||
continue;
|
||||
}
|
||||
double x = static_cast<double>(rand()) / RAND_MAX;
|
||||
double y = static_cast<double>(rand()) / RAND_MAX;
|
||||
double distance = sqrt(x * x + y * y);
|
||||
int px = x * pi_generator->width();
|
||||
int py = (1.0 - y) * pi_generator->height();
|
||||
uint32_t color = pixel_bits[pi_generator->width() * py + px];
|
||||
if (distance < 1.0) {
|
||||
// Set color to blue.
|
||||
++count;
|
||||
pi_generator->pi_ = 4.0 * count / i;
|
||||
color += 4 << kBlueShift;
|
||||
color &= kBlueMask;
|
||||
} else {
|
||||
// Set color to red.
|
||||
color += 4 << kRedShift;
|
||||
color &= kRedMask;
|
||||
}
|
||||
pixel_bits[pi_generator->width() * py + px] = color | kOpaqueColorMask;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// The Module class. The browser calls the CreateInstance() method to create
|
||||
// an instance of your NaCl module on the web page. The browser creates a new
|
||||
// instance for each <embed> tag with type="application/x-nacl".
|
||||
class OsmandModule : public pp::Module {
|
||||
public:
|
||||
OsmandModule() : pp::Module() {}
|
||||
virtual ~OsmandModule() {}
|
||||
|
||||
// Create and return a PiGeneratorInstance object.
|
||||
virtual pp::Instance* CreateInstance(PP_Instance instance) {
|
||||
return new PiGenerator(instance);
|
||||
}
|
||||
};
|
||||
} // namespace osmand
|
||||
|
||||
// Factory function called by the browser when the module is first loaded.
|
||||
// The browser keeps a singleton of this module. It calls the
|
||||
// CreateInstance() method on the object you return to make instances. There
|
||||
// is one instance per <embed> tag on the page. This is the main binding
|
||||
// point for your NaCl module with the browser.
|
||||
namespace pp {
|
||||
Module* CreateModule() {
|
||||
return new osmand::OsmandModule();
|
||||
}
|
||||
} // namespace pp
|
|
@ -1,116 +0,0 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef OSMAND_NACL_H_
|
||||
#define OSMAND_NACL_H_
|
||||
|
||||
#include <pthread.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "ppapi/cpp/graphics_2d.h"
|
||||
#include "ppapi/cpp/image_data.h"
|
||||
#include "ppapi/cpp/instance.h"
|
||||
#include "ppapi/cpp/rect.h"
|
||||
#include "ppapi/cpp/size.h"
|
||||
|
||||
namespace osmand {
|
||||
|
||||
// The Instance class. One of these exists for each instance of your NaCl
|
||||
// module on the web page. The browser will ask the Module object to create
|
||||
// a new Instance for each occurrence of the <embed> tag that has these
|
||||
// attributes:
|
||||
// type="application/x-nacl"
|
||||
// nacl="pi_generator.nmf"
|
||||
class PiGenerator : public pp::Instance {
|
||||
public:
|
||||
explicit PiGenerator(PP_Instance instance);
|
||||
virtual ~PiGenerator();
|
||||
|
||||
// Start up the ComputePi() thread.
|
||||
virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
|
||||
|
||||
// Update the graphics context to the new size, and regenerate |pixel_buffer_|
|
||||
// to fit the new size as well.
|
||||
virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip);
|
||||
|
||||
// Called by the browser to handle the postMessage() call in Javascript.
|
||||
// The message in this case is expected to contain the string 'paint', and
|
||||
// if so this invokes the Paint() function. If |var_message| is not a string
|
||||
// type, or contains something other than 'paint', this method posts an
|
||||
// invalid value for Pi (-1.0) back to the browser.
|
||||
virtual void HandleMessage(const pp::Var& var_message);
|
||||
|
||||
// Return a pointer to the pixels represented by |pixel_buffer_|. When this
|
||||
// method returns, the underlying |pixel_buffer_| object is locked. This
|
||||
// call must have a matching UnlockPixels() or various threading errors
|
||||
// (e.g. deadlock) will occur.
|
||||
uint32_t* LockPixels();
|
||||
// Release the image lock acquired by LockPixels().
|
||||
void UnlockPixels() const;
|
||||
|
||||
// Flushes its contents of |pixel_buffer_| to the 2D graphics context. The
|
||||
// ComputePi() thread fills in |pixel_buffer_| pixels as it computes Pi.
|
||||
// This method is called by HandleMessage when a message containing 'paint'
|
||||
// is received. Echos the current value of pi as computed by the Monte Carlo
|
||||
// method by posting the value back to the browser.
|
||||
void Paint();
|
||||
|
||||
bool quit() const {
|
||||
return quit_;
|
||||
}
|
||||
|
||||
// |pi_| is computed in the ComputePi() thread.
|
||||
double pi() const {
|
||||
return pi_;
|
||||
}
|
||||
|
||||
int width() const {
|
||||
return pixel_buffer_ ? pixel_buffer_->size().width() : 0;
|
||||
}
|
||||
int height() const {
|
||||
return pixel_buffer_ ? pixel_buffer_->size().height() : 0;
|
||||
}
|
||||
|
||||
// Indicate whether a flush is pending. This can only be called from the
|
||||
// main thread; it is not thread safe.
|
||||
bool flush_pending() const {
|
||||
return flush_pending_;
|
||||
}
|
||||
void set_flush_pending(bool flag) {
|
||||
flush_pending_ = flag;
|
||||
}
|
||||
|
||||
private:
|
||||
// Create and initialize the 2D context used for drawing.
|
||||
void CreateContext(const pp::Size& size);
|
||||
// Destroy the 2D drawing context.
|
||||
void DestroyContext();
|
||||
// Push the pixels to the browser, then attempt to flush the 2D context. If
|
||||
// there is a pending flush on the 2D context, then update the pixels only
|
||||
// and do not flush.
|
||||
void FlushPixelBuffer();
|
||||
|
||||
bool IsContextValid() const {
|
||||
return graphics_2d_context_ != NULL;
|
||||
}
|
||||
|
||||
mutable pthread_mutex_t pixel_buffer_mutex_;
|
||||
pp::Graphics2D* graphics_2d_context_;
|
||||
pp::ImageData* pixel_buffer_;
|
||||
bool flush_pending_;
|
||||
bool quit_;
|
||||
pthread_t compute_pi_thread_;
|
||||
double pi_;
|
||||
|
||||
// ComputePi() estimates Pi using Monte Carlo method and it is executed by a
|
||||
// separate thread created in SetWindow(). ComputePi() puts kMaxPointCount
|
||||
// points inside the square whose length of each side is 1.0, and calculates
|
||||
// the ratio of the number of points put inside the inscribed quadrant divided
|
||||
// by the total number of random points to get Pi/4.
|
||||
static void* ComputePi(void* param);
|
||||
};
|
||||
|
||||
} // namespace osmand
|
||||
|
||||
#endif // OSMAND_NACL_H
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,709 +0,0 @@
|
|||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <expat.h>
|
||||
#include "osmand_log.h"
|
||||
#include "common.h"
|
||||
#include "renderRules.h"
|
||||
|
||||
|
||||
/**
|
||||
* Parse the color string, and return the corresponding color-int.
|
||||
* Supported formats are:
|
||||
* #RRGGBB
|
||||
* #AARRGGBB
|
||||
*/
|
||||
int parseColor(string colorString) {
|
||||
if (colorString[0] == '#') {
|
||||
// Use a long to avoid rollovers on #ffXXXXXX
|
||||
char** end;
|
||||
long color = strtol(colorString.c_str() + 1, NULL, 16);
|
||||
if (colorString.size() == 7) {
|
||||
// Set the alpha value
|
||||
color |= 0x00000000ff000000;
|
||||
} else if (colorString.size() != 9) {
|
||||
osmand_log_print(LOG_ERROR, "Unknown color %s", colorString.c_str());
|
||||
}
|
||||
return (int) color;
|
||||
}
|
||||
osmand_log_print(LOG_ERROR, "Unknown color %s", colorString.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
string colorToString(int color) {
|
||||
char c[9];
|
||||
if ((0xFF000000 & color) == 0xFF000000) {
|
||||
sprintf(c, "%x", (color & 0x00FFFFFF));
|
||||
} else {
|
||||
sprintf(c, "%x", color);
|
||||
}
|
||||
return string(c);
|
||||
}
|
||||
|
||||
|
||||
RenderingRule::RenderingRule(map<string, string>& attrs, RenderingRulesStorage* storage) {
|
||||
storage->childRules.push_back(this);
|
||||
properties.reserve(attrs.size());
|
||||
intProperties.assign(attrs.size(), -1);
|
||||
map<string, string>::iterator it = attrs.begin();
|
||||
int i = 0;
|
||||
for (; it != attrs.end(); it++) {
|
||||
RenderingRuleProperty* property = storage->PROPS.getProperty(it->first.c_str());
|
||||
if (property == NULL) {
|
||||
osmand_log_print(LOG_ERROR, "Property %s was not found in registry", it->first.c_str());
|
||||
return ;
|
||||
}
|
||||
properties.push_back(property);
|
||||
|
||||
if (property->isString()) {
|
||||
intProperties[i] = storage->getDictionaryValue(it->second);
|
||||
} else if (property->isFloat()) {
|
||||
if (floatProperties.size() == 0) {
|
||||
// lazy creates
|
||||
floatProperties.assign(attrs.size(), - 1);
|
||||
}
|
||||
floatProperties[i] = property->parseFloatValue(it->second);
|
||||
} else {
|
||||
intProperties[i] = property->parseIntValue(it->second);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
string RenderingRule::getStringPropertyValue(string property, RenderingRulesStorage* storage) {
|
||||
int i = getPropertyIndex(property);
|
||||
if (i >= 0) {
|
||||
return storage->getStringValue(intProperties[i]);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
float RenderingRule::getFloatPropertyValue(string property) {
|
||||
int i = getPropertyIndex(property);
|
||||
if (i >= 0) {
|
||||
return floatProperties[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
string RenderingRule::getColorPropertyValue(string property) {
|
||||
int i = getPropertyIndex(property);
|
||||
if (i >= 0) {
|
||||
return colorToString(intProperties[i]);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
int RenderingRule::getIntPropertyValue(string property) {
|
||||
int i = getPropertyIndex(property);
|
||||
if (i >= 0) {
|
||||
return intProperties[i];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
RenderingRule* RenderingRulesStorage::getRule(int state, int itag, int ivalue) {
|
||||
UNORDERED(map)<int, RenderingRule*>::iterator it = (tagValueGlobalRules[state]).find(
|
||||
(itag << SHIFT_TAG_VAL) | ivalue);
|
||||
if (it == tagValueGlobalRules[state].end()) {
|
||||
return NULL;
|
||||
}
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
|
||||
void RenderingRulesStorage::registerGlobalRule(RenderingRule* rr, int state) {
|
||||
int tag = rr->getIntPropertyValue(this->PROPS.R_TAG->attrName);
|
||||
if (tag == -1) {
|
||||
osmand_log_print(LOG_ERROR, "Attribute tag should be specified for root filter ");
|
||||
}
|
||||
int value = rr->getIntPropertyValue(this->PROPS.R_VALUE->attrName);
|
||||
if (value == -1) {
|
||||
// attrsMap.toString()
|
||||
osmand_log_print(LOG_ERROR, "Attribute tag should be specified for root filter ");
|
||||
}
|
||||
int key = (tag << SHIFT_TAG_VAL) + value;
|
||||
RenderingRule* toInsert = rr;
|
||||
RenderingRule* previous = tagValueGlobalRules[state][key];
|
||||
|
||||
if (previous != NULL) {
|
||||
// all root rules should have at least tag/value
|
||||
toInsert = createTagValueRootWrapperRule(key, previous);
|
||||
toInsert->ifElseChildren.push_back(rr);
|
||||
}
|
||||
tagValueGlobalRules[state][key] = toInsert;
|
||||
}
|
||||
|
||||
RenderingRule* RenderingRulesStorage::createTagValueRootWrapperRule(int tagValueKey, RenderingRule* previous) {
|
||||
if (previous->properties.size() > 2) {
|
||||
map<string, string> m;
|
||||
m["tag"] = getTagString(tagValueKey);
|
||||
m["value"] = getValueString(tagValueKey);
|
||||
RenderingRule* toInsert = new RenderingRule(m, this);
|
||||
toInsert->ifElseChildren.push_back(previous);
|
||||
return toInsert;
|
||||
} else {
|
||||
return previous;
|
||||
}
|
||||
}
|
||||
|
||||
struct GroupRules {
|
||||
RenderingRule* singleRule;
|
||||
map<string, string> groupAttributes;
|
||||
vector<RenderingRule*> children;
|
||||
vector<GroupRules> childrenGroups;
|
||||
|
||||
GroupRules(RenderingRule* singleRule = NULL) : singleRule(singleRule) {
|
||||
}
|
||||
|
||||
inline bool isGroup(){
|
||||
return singleRule == NULL;
|
||||
}
|
||||
|
||||
void addGroupFilter(RenderingRule* rr) {
|
||||
for (vector<RenderingRule*>::iterator ch = children.begin(); ch != children.end(); ch++) {
|
||||
(*ch)->ifChildren.push_back(rr);
|
||||
}
|
||||
for (vector<GroupRules>::iterator gch = childrenGroups.begin(); gch != childrenGroups.end(); gch++) {
|
||||
gch->addGroupFilter(rr);
|
||||
}
|
||||
}
|
||||
|
||||
void registerGlobalRules(RenderingRulesStorage* storage, int state) {
|
||||
for (vector<RenderingRule*>::iterator ch = children.begin(); ch != children.end(); ch++) {
|
||||
storage->registerGlobalRule(*ch, state);
|
||||
}
|
||||
for (vector<GroupRules>::iterator gch = childrenGroups.begin(); gch != childrenGroups.end(); gch++) {
|
||||
gch->registerGlobalRules(storage, state);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class RenderingRulesHandler {
|
||||
friend class RenderingRulesStorage;
|
||||
int state;
|
||||
stack<GroupRules> st;
|
||||
RenderingRulesStorageResolver* resolver;
|
||||
RenderingRulesStorage* dependsStorage;
|
||||
RenderingRulesStorage* storage;
|
||||
|
||||
|
||||
RenderingRulesHandler(RenderingRulesStorageResolver* resolver, RenderingRulesStorage* storage) :
|
||||
storage(storage), resolver(resolver), dependsStorage(NULL) {
|
||||
}
|
||||
|
||||
RenderingRulesStorage* getDependsStorage() {
|
||||
return dependsStorage;
|
||||
}
|
||||
|
||||
static map<string, string>& parseAttributes(const char **atts, map<string, string>& m,
|
||||
RenderingRulesStorage* st) {
|
||||
while (*atts != NULL) {
|
||||
string vl = string(atts[1]);
|
||||
if(vl.size() > 1 && vl[0] == '$') {
|
||||
vl = st->renderingConstants[vl.substr(1, vl.size() - 1)];
|
||||
}
|
||||
m[string(atts[0])] = string(atts[1]);
|
||||
atts += 2;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
static void startElementHandler(void *data, const char *tag, const char **atts) {
|
||||
RenderingRulesHandler* t = (RenderingRulesHandler*) data;
|
||||
int len = strlen(tag);
|
||||
string name(tag);
|
||||
if (len == 6 && "filter" == name) {
|
||||
map<string, string> attrsMap;
|
||||
if (t->st.size() > 0 && t->st.top().isGroup()) {
|
||||
attrsMap.insert(t->st.top().groupAttributes.begin(), t->st.top().groupAttributes.end());
|
||||
}
|
||||
parseAttributes(atts, attrsMap, t->storage);
|
||||
RenderingRule* renderingRule = new RenderingRule(attrsMap,t->storage);
|
||||
if (t->st.size() > 0 && t->st.top().isGroup()) {
|
||||
t->st.top().children.push_back(renderingRule);
|
||||
} else if (t->st.size() > 0 && !t->st.top().isGroup()) {
|
||||
RenderingRule* parent = t->st.top().singleRule;
|
||||
t->st.top().singleRule->ifElseChildren.push_back(renderingRule);
|
||||
} else {
|
||||
t->storage->registerGlobalRule(renderingRule, t->state);
|
||||
|
||||
}
|
||||
GroupRules gr(renderingRule);
|
||||
t->st.push(gr);
|
||||
} else if ("groupFilter" == name) { //$NON-NLS-1$
|
||||
map<string, string> attrsMap;
|
||||
parseAttributes(atts, attrsMap, t->storage);
|
||||
RenderingRule* renderingRule = new RenderingRule(attrsMap,t->storage);
|
||||
if (t->st.size() > 0 && t->st.top().isGroup()) {
|
||||
GroupRules parent = ((GroupRules) t->st.top());
|
||||
t->st.top().addGroupFilter(renderingRule);
|
||||
} else if (t->st.size() > 0 && !t->st.top().isGroup()) {
|
||||
t->st.top().singleRule->ifChildren.push_back(renderingRule);
|
||||
} else {
|
||||
osmand_log_print(LOG_ERROR, "Group filter without parent");
|
||||
}
|
||||
t->st.push(GroupRules(renderingRule));
|
||||
} else if ("group" == name) { //$NON-NLS-1$
|
||||
GroupRules groupRules;
|
||||
if (t->st.size() > 0 && t->st.top().isGroup()) {
|
||||
groupRules.groupAttributes.insert(t->st.top().groupAttributes.begin(), t->st.top().groupAttributes.end());
|
||||
}
|
||||
parseAttributes(atts, groupRules.groupAttributes, t->storage);
|
||||
t->st.push(groupRules);
|
||||
} else if ("order" == name) { //$NON-NLS-1$
|
||||
t->state = RenderingRulesStorage::ORDER_RULES;
|
||||
} else if ("text" == name) { //$NON-NLS-1$
|
||||
t->state = RenderingRulesStorage::TEXT_RULES;
|
||||
} else if ("point" == name) { //$NON-NLS-1$
|
||||
t->state = RenderingRulesStorage::POINT_RULES;
|
||||
} else if ("line" == name) { //$NON-NLS-1$
|
||||
t->state = RenderingRulesStorage::LINE_RULES;
|
||||
} else if ("polygon" == name) { //$NON-NLS-1$
|
||||
t->state = RenderingRulesStorage::POLYGON_RULES;
|
||||
} else if ("renderingConstant" == name) { //$NON-NLS-1$
|
||||
map<string, string> attrsMap;
|
||||
parseAttributes(atts, attrsMap, t->storage);
|
||||
t->storage->renderingConstants[attrsMap["name"]] = attrsMap["value"];
|
||||
} else if ("renderingAttribute" == name) { //$NON-NLS-1$
|
||||
map<string, string> attrsMap;
|
||||
parseAttributes(atts, attrsMap, t->storage);
|
||||
string attr = attrsMap["name"];
|
||||
map<string, string> empty;
|
||||
RenderingRule* root = new RenderingRule(empty,t->storage);
|
||||
t->storage->renderingAttributes[attr] = root;
|
||||
t->st.push(GroupRules(root));
|
||||
} else if ("renderingProperty" == name) {
|
||||
map<string, string> attrsMap;
|
||||
parseAttributes(atts, attrsMap, t->storage);
|
||||
string attr = attrsMap["attr"];
|
||||
RenderingRuleProperty* prop;
|
||||
string type = attrsMap["type"];
|
||||
if ("boolean" == type) {
|
||||
prop = RenderingRuleProperty::createInputBooleanProperty(attr);
|
||||
} else if ("string" == type) {
|
||||
prop = RenderingRuleProperty::createInputStringProperty(attr);
|
||||
} else {
|
||||
prop = RenderingRuleProperty::createInputIntProperty(attr);
|
||||
}
|
||||
prop->description = attrsMap["description"];
|
||||
prop->name = attrsMap["name"];
|
||||
string possible = attrsMap["possibleValues"];
|
||||
if (possible != "") {
|
||||
int n;
|
||||
int p = 0;
|
||||
while ((n = possible.find(',', p)) != string::npos) {
|
||||
prop->possibleValues.push_back(possible.substr(p, n));
|
||||
p = n + 1;
|
||||
}
|
||||
prop->possibleValues.push_back(possible.substr(p));
|
||||
}
|
||||
t->storage->PROPS.registerRule(prop);
|
||||
} else if ("renderingStyle" == name) {
|
||||
map<string, string> attrsMap;
|
||||
parseAttributes(atts, attrsMap, t->storage);
|
||||
string depends = attrsMap["depends"];
|
||||
if (depends.size() > 0 && t->resolver != NULL) {
|
||||
t->dependsStorage = t->resolver->resolve(depends, t->resolver);
|
||||
}
|
||||
if (t->dependsStorage != NULL) {
|
||||
// copy dictionary
|
||||
t->storage->dictionary = t->dependsStorage->dictionary;
|
||||
t->storage->dictionaryMap = t->dependsStorage->dictionaryMap;
|
||||
t->storage->PROPS.merge(t->dependsStorage->PROPS);
|
||||
} else if (depends.size() > 0) {
|
||||
osmand_log_print(LOG_ERROR, "!Dependent rendering style was not resolved : %s", depends.c_str());
|
||||
}
|
||||
//renderingName = attrsMap["name"];
|
||||
} else {
|
||||
osmand_log_print(LOG_WARN, "Unknown tag : %s", name.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void endElementHandler(void *data, const char *tag) {
|
||||
int len = strlen(tag);
|
||||
RenderingRulesHandler* t = (RenderingRulesHandler*) data;
|
||||
string name(tag);
|
||||
if ("filter" == name) { //$NON-NLS-1$
|
||||
t->st.pop();
|
||||
} else if ("group" == name) { //$NON-NLS-1$
|
||||
GroupRules group = t->st.top();
|
||||
t->st.pop();
|
||||
if (t->st.size() == 0) {
|
||||
group.registerGlobalRules(t->storage,t->state);
|
||||
} else if(t->st.top().isGroup()){
|
||||
t->st.top().childrenGroups.push_back(group);
|
||||
}
|
||||
} else if ("groupFilter" == name) { //$NON-NLS-1$
|
||||
t->st.pop();
|
||||
} else if ("renderingAttribute" == name) { //$NON-NLS-1$
|
||||
t->st.pop();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
void RenderingRule::printDebugRenderingRule(string indent, RenderingRulesStorage * st) {
|
||||
indent += " ";
|
||||
printf("\n%s", indent.c_str());
|
||||
vector<RenderingRuleProperty*>::iterator pp = properties.begin();
|
||||
for (; pp != properties.end(); pp++) {
|
||||
printf(" %s=", (*pp)->attrName.c_str());
|
||||
if ((*pp)->isString()) {
|
||||
printf("\"%s\"", getStringPropertyValue((*pp)->attrName, st).c_str());
|
||||
} else if ((*pp)->isFloat()) {
|
||||
printf("%f", getFloatPropertyValue((*pp)->attrName));
|
||||
} else if ((*pp)->isColor()) {
|
||||
printf("%s", getColorPropertyValue((*pp)->attrName).c_str());
|
||||
} else if ((*pp)->isIntParse()) {
|
||||
printf("%d", getIntPropertyValue((*pp)->attrName));
|
||||
}
|
||||
}
|
||||
vector<RenderingRule*>::iterator it = ifElseChildren.begin();
|
||||
for (; it != ifElseChildren.end(); it++) {
|
||||
(*it)->printDebugRenderingRule(indent, st);
|
||||
}
|
||||
}
|
||||
void RenderingRulesStorage::printDebug(int state) {
|
||||
UNORDERED(map)<int, RenderingRule*>::iterator it = tagValueGlobalRules[state].begin();
|
||||
for (; it != tagValueGlobalRules[state].end(); it++) {
|
||||
printf("\n\n%s : %s", getTagString(it->first).c_str(), getValueString(it->first).c_str());
|
||||
it->second->printDebugRenderingRule(string(""), this);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingRulesStorage::parseRulesFromXmlInputStream(const char* filename, RenderingRulesStorageResolver* resolver) {
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
RenderingRulesHandler* handler = new RenderingRulesHandler(resolver, this);
|
||||
XML_SetUserData(parser, handler);
|
||||
XML_SetElementHandler(parser, RenderingRulesHandler::startElementHandler, RenderingRulesHandler::endElementHandler);
|
||||
FILE *file = fopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
osmand_log_print(LOG_ERROR, "File can not be open %s", filename);
|
||||
XML_ParserFree(parser);
|
||||
delete handler;
|
||||
return;
|
||||
}
|
||||
char buffer[512];
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
fgets(buffer, sizeof(buffer), file);
|
||||
int len = strlen(buffer);
|
||||
if (feof(file) != 0) {
|
||||
done = true;
|
||||
}
|
||||
if (XML_Parse(parser, buffer, len, done) == XML_STATUS_ERROR) {
|
||||
fclose(file);
|
||||
XML_ParserFree(parser);
|
||||
delete handler;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RenderingRulesStorage* depends = handler->getDependsStorage();
|
||||
if (depends != NULL) {
|
||||
// merge results
|
||||
// dictionary and props are already merged
|
||||
map<std::string, RenderingRule*>::iterator it = depends->renderingAttributes.begin();
|
||||
for(;it != depends->renderingAttributes.end(); it++) {
|
||||
map<std::string, RenderingRule*>::iterator o = renderingAttributes.find(it->first);
|
||||
if (o != renderingAttributes.end()) {
|
||||
std::vector<RenderingRule*>::iterator list = it->second->ifElseChildren.begin();
|
||||
for (;list != it->second->ifElseChildren.end(); list++) {
|
||||
o->second->ifElseChildren.push_back(*list);
|
||||
}
|
||||
} else {
|
||||
renderingAttributes[it->first] = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < SIZE_STATES; i++) {
|
||||
if (depends->tagValueGlobalRules[i].empty()) {
|
||||
continue;
|
||||
}
|
||||
UNORDERED(map)<int, RenderingRule*>::iterator it = depends->tagValueGlobalRules[i].begin();
|
||||
for (; it != depends->tagValueGlobalRules[i].end(); it++) {
|
||||
UNORDERED(map)<int, RenderingRule*>::iterator o = tagValueGlobalRules[i].find(it->first);
|
||||
RenderingRule* toInsert = it->second;
|
||||
if (o != tagValueGlobalRules[i].end()) {
|
||||
toInsert = createTagValueRootWrapperRule(it->first, o->second);
|
||||
toInsert->ifElseChildren.push_back(it->second);
|
||||
}
|
||||
tagValueGlobalRules[i][it->first] = toInsert;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
XML_ParserFree(parser);
|
||||
delete handler;
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
|
||||
RenderingRuleSearchRequest::RenderingRuleSearchRequest(RenderingRulesStorage* storage) {
|
||||
this->storage = storage;
|
||||
PROPS = &(this->storage->PROPS);
|
||||
this->values.resize(PROPS->properties.size(), 0);
|
||||
this->fvalues.resize(PROPS->properties.size(), 0);
|
||||
UNORDERED(map)<string, RenderingRuleProperty*>::iterator it = PROPS->properties.begin();
|
||||
for (; it != PROPS->properties.end(); it++) {
|
||||
if (!it->second->isColor()) {
|
||||
values[it->second->id] = -1;
|
||||
}
|
||||
}
|
||||
setBooleanFilter(PROPS->R_TEST, true);
|
||||
saveState();
|
||||
}
|
||||
|
||||
void RenderingRuleSearchRequest::saveState() {
|
||||
this->savedFvalues = fvalues;
|
||||
this->savedValues = values;
|
||||
}
|
||||
|
||||
RenderingRuleSearchRequest::~RenderingRuleSearchRequest() {
|
||||
}
|
||||
|
||||
int RenderingRuleSearchRequest::getIntPropertyValue(RenderingRuleProperty* prop) {
|
||||
if (prop == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return values[prop->id];
|
||||
}
|
||||
|
||||
int RenderingRuleSearchRequest::getIntPropertyValue(RenderingRuleProperty* prop, int def) {
|
||||
if (prop == NULL || values[prop->id] == -1) {
|
||||
return def;
|
||||
}
|
||||
return values[prop->id];
|
||||
}
|
||||
|
||||
std::string RenderingRuleSearchRequest::getStringPropertyValue(RenderingRuleProperty* prop) {
|
||||
if (prop == NULL) {
|
||||
return std::string();
|
||||
}
|
||||
int s = values[prop->id];
|
||||
return storage->getDictionaryValue(s);
|
||||
}
|
||||
|
||||
float RenderingRuleSearchRequest::getFloatPropertyValue(RenderingRuleProperty* prop) {
|
||||
if (prop == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return fvalues[prop->id];
|
||||
}
|
||||
|
||||
void RenderingRuleSearchRequest::setStringFilter(RenderingRuleProperty* p, std::string filter) {
|
||||
if (p != NULL) {
|
||||
// assert p->input;
|
||||
values[p->id] = storage->getDictionaryValue(filter);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingRuleSearchRequest::setIntFilter(RenderingRuleProperty* p, int filter) {
|
||||
if (p != NULL) {
|
||||
// assert p->input;
|
||||
values[p->id] = filter;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingRuleSearchRequest::externalInitialize(vector<int>& vs, vector<float>& fvs, vector<int>& sVs, vector<float>& sFvs){
|
||||
this->values = vs;
|
||||
this->fvalues = fvs;
|
||||
this->savedValues = sVs;
|
||||
this->savedFvalues = sFvs;
|
||||
|
||||
}
|
||||
void RenderingRuleSearchRequest::clearIntvalue(RenderingRuleProperty* p) {
|
||||
if (p != NULL) {
|
||||
// assert !p->input;
|
||||
values[p->id] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingRuleSearchRequest::setBooleanFilter(RenderingRuleProperty* p, bool filter) {
|
||||
if (p != NULL) {
|
||||
// assert p->input;
|
||||
values[p->id] = filter ? TRUE_VALUE : FALSE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
RenderingRulesStorageProperties* RenderingRuleSearchRequest::props() {
|
||||
return PROPS;
|
||||
}
|
||||
|
||||
bool RenderingRuleSearchRequest::searchRule(int state) {
|
||||
return search(state, true);
|
||||
}
|
||||
|
||||
bool RenderingRuleSearchRequest::searchRenderingAttribute(string attribute) {
|
||||
searchResult = false;
|
||||
RenderingRule* rule = storage->getRenderingAttributeRule(attribute);
|
||||
if (rule == NULL) {
|
||||
return false;
|
||||
}
|
||||
searchResult = visitRule(rule, true);
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
bool RenderingRuleSearchRequest::search(int state, bool loadOutput) {
|
||||
searchResult = false;
|
||||
int tagKey = values[PROPS->R_TAG->id];
|
||||
int valueKey = values[PROPS->R_VALUE->id];
|
||||
bool result = searchInternal(state, tagKey, valueKey, loadOutput);
|
||||
if (result) {
|
||||
searchResult = true;
|
||||
return true;
|
||||
}
|
||||
result = searchInternal(state, tagKey, 0, loadOutput);
|
||||
if (result) {
|
||||
searchResult = true;
|
||||
return true;
|
||||
}
|
||||
result = searchInternal(state, 0, 0, loadOutput);
|
||||
if (result) {
|
||||
searchResult = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RenderingRuleSearchRequest::searchInternal(int state, int tagKey, int valueKey, bool loadOutput) {
|
||||
values[PROPS->R_TAG->id] = tagKey;
|
||||
values[PROPS->R_VALUE->id] = valueKey;
|
||||
RenderingRule* accept = storage->getRule(state, tagKey, valueKey);
|
||||
if (accept == NULL) {
|
||||
return false;
|
||||
}
|
||||
bool match = visitRule(accept, loadOutput);
|
||||
return match;
|
||||
}
|
||||
|
||||
bool RenderingRuleSearchRequest::visitRule(RenderingRule* rule, bool loadOutput) {
|
||||
std::vector<RenderingRuleProperty*> properties = rule->properties;
|
||||
int propLen = rule->properties.size();
|
||||
for (int i = 0; i < propLen; i++) {
|
||||
RenderingRuleProperty* rp = properties[i];
|
||||
if (rp != NULL && rp->input) {
|
||||
bool match;
|
||||
if (rp->isFloat()) {
|
||||
match = rule->floatProperties[i] == fvalues[rp->id];
|
||||
} else if (rp == PROPS->R_MINZOOM) {
|
||||
match = rule->intProperties[i] <= values[rp->id];
|
||||
} else if (rp == PROPS->R_MAXZOOM) {
|
||||
match = rule->intProperties[i] >= values[rp->id];
|
||||
} else if (rp == PROPS->R_ADDITIONAL) {
|
||||
if (obj == NULL) {
|
||||
match = true;
|
||||
} else {
|
||||
std::string val = storage->getDictionaryValue(rule->intProperties[i]);
|
||||
int i = val.find('=');
|
||||
if (i >= 0) {
|
||||
match = obj->containsAdditional(val.substr(0, i), val.substr(i + 1));
|
||||
} else {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match = rule->intProperties[i] == values[rp->id];
|
||||
}
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!loadOutput) {
|
||||
return true;
|
||||
}
|
||||
// accept it
|
||||
for (int i = 0; i < propLen; i++) {
|
||||
RenderingRuleProperty* rp = properties[i];
|
||||
if (rp != NULL && !rp->input) {
|
||||
searchResult = true;
|
||||
if (rp->isFloat()) {
|
||||
fvalues[rp->id] = rule->floatProperties[i];
|
||||
} else {
|
||||
values[rp->id] = rule->intProperties[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
size_t j;
|
||||
for (j = 0; j < rule->ifElseChildren.size(); j++) {
|
||||
bool match = visitRule(rule->ifElseChildren.at(j), loadOutput);
|
||||
if (match) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < rule->ifChildren.size(); j++) {
|
||||
visitRule(rule->ifChildren.at(j), loadOutput);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void RenderingRuleSearchRequest::clearState() {
|
||||
obj = NULL;
|
||||
values = savedValues;
|
||||
fvalues = savedFvalues;
|
||||
}
|
||||
|
||||
void RenderingRuleSearchRequest::setInitialTagValueZoom(std::string tag, std::string value, int zoom, MapDataObject* obj) {
|
||||
clearState();
|
||||
this->obj = obj;
|
||||
setIntFilter(PROPS->R_MINZOOM, zoom);
|
||||
setIntFilter(PROPS->R_MAXZOOM, zoom);
|
||||
setStringFilter(PROPS->R_TAG, tag);
|
||||
setStringFilter(PROPS->R_VALUE, value);
|
||||
}
|
||||
|
||||
void RenderingRuleSearchRequest::setTagValueZoomLayer(std::string tag, std::string val, int zoom, int layer, MapDataObject* obj) {
|
||||
this->obj = obj;
|
||||
setIntFilter(PROPS->R_MINZOOM, zoom);
|
||||
setIntFilter(PROPS->R_MAXZOOM, zoom);
|
||||
setIntFilter(PROPS->R_LAYER, layer);
|
||||
setStringFilter(PROPS->R_TAG, tag);
|
||||
setStringFilter(PROPS->R_VALUE, val);
|
||||
}
|
||||
|
||||
bool RenderingRuleSearchRequest::isSpecified(RenderingRuleProperty* p) {
|
||||
if (p->isFloat()) {
|
||||
return fvalues[p->id] != 0;
|
||||
} else {
|
||||
int val = values[p->id];
|
||||
if (p->isColor()) {
|
||||
return val != 0;
|
||||
} else {
|
||||
return val != -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingRuleSearchRequest::printDebugResult() {
|
||||
if (searchResult) {
|
||||
printf("\n Found : ");
|
||||
UNORDERED(map)<string, RenderingRuleProperty*>::iterator it = PROPS->properties.begin();
|
||||
for (; it != PROPS->properties.end(); ++it) {
|
||||
RenderingRuleProperty* rp = it->second;
|
||||
if (!rp->input && isSpecified(rp)) {
|
||||
printf(" %s=", rp->attrName.c_str());
|
||||
if (rp->isString()) {
|
||||
printf("\"%s\"", getStringPropertyValue(rp).c_str());
|
||||
} else if (rp->isFloat()) {
|
||||
printf("%f", getFloatPropertyValue(rp));
|
||||
} else if (rp->isColor()) {
|
||||
printf("%s", colorToString(getIntPropertyValue(rp)).c_str());
|
||||
} else if (rp->isIntParse()) {
|
||||
printf("%d", getIntPropertyValue(rp));
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("\nNot found\n");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,552 +0,0 @@
|
|||
#ifndef _OSMAND_RENDER_RULES_H
|
||||
#define _OSMAND_RENDER_RULES_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "common.h"
|
||||
#include "mapObjects.h"
|
||||
|
||||
|
||||
/**
|
||||
* Parse the color string, and return the corresponding color-int.
|
||||
* Supported formats are:
|
||||
* #RRGGBB
|
||||
* #AARRGGBB
|
||||
*/
|
||||
int parseColor(string colorString) ;
|
||||
string colorToString(int color);
|
||||
|
||||
const static int TRUE_VALUE = 1;
|
||||
const static int FALSE_VALUE = 0;
|
||||
|
||||
// Foward declaration of classes
|
||||
class RenderingRuleProperty;
|
||||
class RenderingRule;
|
||||
class RenderingRulesStorage;
|
||||
class RenderingRulesHandler;
|
||||
class RenderingRulesStorageResolver;
|
||||
class RenderingRulesStorageProperties;
|
||||
class RenderingRuleSearchRequest;
|
||||
|
||||
class RenderingRuleProperty
|
||||
{
|
||||
private:
|
||||
int type;
|
||||
const static int INT_TYPE = 1;
|
||||
const static int FLOAT_TYPE = 2;
|
||||
const static int STRING_TYPE = 3;
|
||||
const static int COLOR_TYPE = 4;
|
||||
const static int BOOLEAN_TYPE = 5;
|
||||
|
||||
public:
|
||||
bool input;
|
||||
std::string attrName;
|
||||
// order in
|
||||
int id;
|
||||
// use for custom rendering rule properties
|
||||
string name;
|
||||
string description;
|
||||
vector<string> possibleValues;
|
||||
|
||||
RenderingRuleProperty(std::string& name, int type, bool input, int id = -1) :
|
||||
type(type), input(input), attrName(name), id(id) {
|
||||
}
|
||||
|
||||
bool isFloat() {
|
||||
return type == FLOAT_TYPE;
|
||||
}
|
||||
|
||||
bool isColor() {
|
||||
return type == COLOR_TYPE;
|
||||
}
|
||||
|
||||
bool isString() {
|
||||
return type == STRING_TYPE;
|
||||
}
|
||||
|
||||
bool isIntParse() {
|
||||
return type == INT_TYPE || type == STRING_TYPE || type == COLOR_TYPE || type == BOOLEAN_TYPE;
|
||||
}
|
||||
|
||||
int parseIntValue(string value) {
|
||||
if (type == INT_TYPE) {
|
||||
return atoi(value.c_str());
|
||||
} else if (type == BOOLEAN_TYPE) {
|
||||
return value == "true" ? TRUE_VALUE : FALSE_VALUE;
|
||||
} else if (type == STRING_TYPE) {
|
||||
// requires dictionary to parse
|
||||
return -1;
|
||||
} else if (type == COLOR_TYPE) {
|
||||
return parseColor(value);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
float parseFloatValue(string value) {
|
||||
if (type == FLOAT_TYPE) {
|
||||
return atof(value.c_str());
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static RenderingRuleProperty* createOutputIntProperty(string name) {
|
||||
return new RenderingRuleProperty(name, INT_TYPE, false);
|
||||
}
|
||||
|
||||
static RenderingRuleProperty* createOutputBooleanProperty(string name) {
|
||||
return new RenderingRuleProperty(name, BOOLEAN_TYPE, false);
|
||||
}
|
||||
|
||||
static RenderingRuleProperty* createInputBooleanProperty(string name) {
|
||||
return new RenderingRuleProperty(name, BOOLEAN_TYPE, true);
|
||||
}
|
||||
|
||||
static RenderingRuleProperty* createOutputFloatProperty(string name) {
|
||||
return new RenderingRuleProperty(name, FLOAT_TYPE, false);
|
||||
}
|
||||
|
||||
static RenderingRuleProperty* createOutputStringProperty(string name) {
|
||||
return new RenderingRuleProperty(name, STRING_TYPE, false);
|
||||
}
|
||||
|
||||
static RenderingRuleProperty* createInputIntProperty(string name) {
|
||||
return new RenderingRuleProperty(name, INT_TYPE, true);
|
||||
}
|
||||
|
||||
static RenderingRuleProperty* createInputColorProperty(string name) {
|
||||
return new RenderingRuleProperty(name, COLOR_TYPE, true);
|
||||
}
|
||||
|
||||
static RenderingRuleProperty* createOutputColorProperty(string name) {
|
||||
return new RenderingRuleProperty(name, COLOR_TYPE, false);
|
||||
}
|
||||
|
||||
static RenderingRuleProperty* createInputStringProperty(string name) {
|
||||
return new RenderingRuleProperty(name, STRING_TYPE, true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class RenderingRule
|
||||
{
|
||||
public:
|
||||
std::vector<RenderingRuleProperty*> properties;
|
||||
std::vector<int> intProperties;
|
||||
std::vector<float> floatProperties;
|
||||
std::vector<RenderingRule*> ifElseChildren;
|
||||
std::vector<RenderingRule*> ifChildren;
|
||||
|
||||
RenderingRule(map<string, string>& attrs, RenderingRulesStorage* storage);
|
||||
void printDebugRenderingRule(string indent, RenderingRulesStorage * st);
|
||||
private :
|
||||
inline int getPropertyIndex(string property) {
|
||||
for (int i = 0; i < properties.size(); i++) {
|
||||
RenderingRuleProperty* prop = properties[i];
|
||||
if (prop->attrName == property) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
public :
|
||||
string getStringPropertyValue(string property, RenderingRulesStorage* storage);
|
||||
|
||||
float getFloatPropertyValue(string property);
|
||||
|
||||
string getColorPropertyValue(string property);
|
||||
|
||||
int getIntPropertyValue(string property);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class RenderingRulesStorageResolver {
|
||||
|
||||
public:
|
||||
virtual RenderingRulesStorage* resolve(string name, RenderingRulesStorageResolver* ref) = 0;
|
||||
|
||||
virtual ~RenderingRulesStorageResolver() {}
|
||||
};
|
||||
|
||||
|
||||
class RenderingRulesStorageProperties
|
||||
{
|
||||
public:
|
||||
RenderingRuleProperty* R_TEST;
|
||||
RenderingRuleProperty* R_TEXT_LENGTH;
|
||||
RenderingRuleProperty* R_REF;
|
||||
RenderingRuleProperty* R_TEXT_SHIELD;
|
||||
RenderingRuleProperty* R_SHADOW_RADIUS;
|
||||
RenderingRuleProperty* R_SHADOW_COLOR;
|
||||
RenderingRuleProperty* R_SHADER;
|
||||
RenderingRuleProperty* R_CAP_3;
|
||||
RenderingRuleProperty* R_CAP_2;
|
||||
RenderingRuleProperty* R_CAP;
|
||||
RenderingRuleProperty* R_CAP_0;
|
||||
RenderingRuleProperty* R_CAP__1;
|
||||
RenderingRuleProperty* R_PATH_EFFECT_3;
|
||||
RenderingRuleProperty* R_PATH_EFFECT_2;
|
||||
RenderingRuleProperty* R_PATH_EFFECT;
|
||||
RenderingRuleProperty* R_PATH_EFFECT_0;
|
||||
RenderingRuleProperty* R_PATH_EFFECT__1;
|
||||
RenderingRuleProperty* R_STROKE_WIDTH_3;
|
||||
RenderingRuleProperty* R_STROKE_WIDTH_2;
|
||||
RenderingRuleProperty* R_STROKE_WIDTH;
|
||||
RenderingRuleProperty* R_STROKE_WIDTH_0;
|
||||
RenderingRuleProperty* R_STROKE_WIDTH__1;
|
||||
RenderingRuleProperty* R_COLOR_3;
|
||||
RenderingRuleProperty* R_COLOR;
|
||||
RenderingRuleProperty* R_COLOR_2;
|
||||
RenderingRuleProperty* R_COLOR_0;
|
||||
RenderingRuleProperty* R_COLOR__1;
|
||||
RenderingRuleProperty* R_TEXT_BOLD;
|
||||
RenderingRuleProperty* R_TEXT_ORDER;
|
||||
RenderingRuleProperty* R_TEXT_MIN_DISTANCE;
|
||||
RenderingRuleProperty* R_TEXT_ON_PATH;
|
||||
RenderingRuleProperty* R_ICON;
|
||||
RenderingRuleProperty* R_LAYER;
|
||||
RenderingRuleProperty* R_ORDER;
|
||||
RenderingRuleProperty* R_TAG;
|
||||
RenderingRuleProperty* R_VALUE;
|
||||
RenderingRuleProperty* R_MINZOOM;
|
||||
RenderingRuleProperty* R_SHADOW_LEVEL;
|
||||
RenderingRuleProperty* R_MAXZOOM;
|
||||
RenderingRuleProperty* R_NIGHT_MODE;
|
||||
RenderingRuleProperty* R_TEXT_DY;
|
||||
RenderingRuleProperty* R_TEXT_SIZE;
|
||||
RenderingRuleProperty* R_TEXT_COLOR;
|
||||
RenderingRuleProperty* R_TEXT_HALO_RADIUS;
|
||||
RenderingRuleProperty* R_TEXT_WRAP_WIDTH;
|
||||
RenderingRuleProperty* R_ADDITIONAL;
|
||||
RenderingRuleProperty* R_OBJECT_TYPE;
|
||||
RenderingRuleProperty* R_POINT;
|
||||
RenderingRuleProperty* R_AREA;
|
||||
RenderingRuleProperty* R_CYCLE;
|
||||
RenderingRuleProperty* R_NAME_TAG;
|
||||
RenderingRuleProperty* R_ATTR_INT_VALUE;
|
||||
RenderingRuleProperty* R_ATTR_COLOR_VALUE;
|
||||
RenderingRuleProperty* R_ATTR_BOOL_VALUE;
|
||||
RenderingRuleProperty* R_ATTR_STRING_VALUE;
|
||||
|
||||
UNORDERED(map)<string, RenderingRuleProperty*> properties;
|
||||
vector<RenderingRuleProperty*> rules;
|
||||
vector<RenderingRuleProperty*> customRules;
|
||||
|
||||
inline RenderingRuleProperty* getProperty(const char* st) {
|
||||
UNORDERED(map)<std::string, RenderingRuleProperty*>::iterator i = properties.find(st);
|
||||
if (i == properties.end()) {
|
||||
return NULL;
|
||||
}
|
||||
return (*i).second;
|
||||
}
|
||||
|
||||
inline RenderingRuleProperty* getProperty(std::string& st) {
|
||||
UNORDERED(map)<std::string, RenderingRuleProperty*>::iterator i = properties.find(st);
|
||||
if (i == properties.end()) {
|
||||
return NULL;
|
||||
}
|
||||
return (*i).second;
|
||||
}
|
||||
|
||||
RenderingRuleProperty* registerRule(RenderingRuleProperty* p) {
|
||||
RenderingRuleProperty* pr = getProperty(p->attrName);
|
||||
if (pr != NULL) {
|
||||
return pr;
|
||||
}
|
||||
RenderingRuleProperty* ps = registerRuleInternal(p);
|
||||
customRules.push_back(ps);
|
||||
return ps;
|
||||
}
|
||||
|
||||
void merge(RenderingRulesStorageProperties& props) {
|
||||
vector<RenderingRuleProperty*>::iterator t = props.customRules.begin();
|
||||
for (; t != props.customRules.end(); t++) {
|
||||
customRules.push_back(*t);
|
||||
properties[(*t)->attrName] = *t;
|
||||
}
|
||||
}
|
||||
|
||||
RenderingRulesStorageProperties(bool initDefault) {
|
||||
if (initDefault) {
|
||||
createDefaultProperties();
|
||||
}
|
||||
}
|
||||
|
||||
~RenderingRulesStorageProperties() {
|
||||
vector<RenderingRuleProperty*>::iterator it = rules.begin();
|
||||
for (; it != rules.end(); it++) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
RenderingRuleProperty* registerRuleInternal(RenderingRuleProperty* p) {
|
||||
if (getProperty(p->attrName) == NULL) {
|
||||
properties[p->attrName] = p;
|
||||
p->id = rules.size();
|
||||
rules.push_back(p);
|
||||
}
|
||||
return getProperty(p->attrName);
|
||||
}
|
||||
|
||||
void createDefaultProperties() {
|
||||
R_TEST = registerRuleInternal(RenderingRuleProperty::createInputBooleanProperty("test"));
|
||||
R_TAG = registerRuleInternal(RenderingRuleProperty::createInputStringProperty("tag"));
|
||||
R_VALUE = registerRuleInternal(RenderingRuleProperty::createInputStringProperty("value"));
|
||||
R_ADDITIONAL = registerRuleInternal(RenderingRuleProperty::createInputStringProperty("additional"));
|
||||
R_MINZOOM = registerRuleInternal(RenderingRuleProperty::createInputIntProperty("minzoom"));
|
||||
R_MAXZOOM = registerRuleInternal(RenderingRuleProperty::createInputIntProperty("maxzoom"));
|
||||
R_NIGHT_MODE = registerRuleInternal(RenderingRuleProperty::createInputBooleanProperty("nightMode"));
|
||||
R_LAYER = registerRuleInternal(RenderingRuleProperty::createInputIntProperty("layer"));
|
||||
R_POINT = registerRuleInternal(RenderingRuleProperty::createInputBooleanProperty("point"));
|
||||
R_AREA = registerRuleInternal(RenderingRuleProperty::createInputBooleanProperty("area"));
|
||||
R_CYCLE = registerRuleInternal(RenderingRuleProperty::createInputBooleanProperty("cycle"));
|
||||
|
||||
R_TEXT_LENGTH = registerRuleInternal(RenderingRuleProperty::createInputIntProperty("textLength"));
|
||||
R_NAME_TAG = registerRuleInternal(RenderingRuleProperty::createInputStringProperty("nameTag"));
|
||||
|
||||
R_ATTR_INT_VALUE = registerRuleInternal(RenderingRuleProperty::createOutputIntProperty("attrIntValue"));
|
||||
R_ATTR_BOOL_VALUE = registerRuleInternal(RenderingRuleProperty::createOutputBooleanProperty("attrBoolValue"));
|
||||
R_ATTR_COLOR_VALUE = registerRuleInternal(RenderingRuleProperty::createOutputColorProperty("attrColorValue"));
|
||||
R_ATTR_STRING_VALUE = registerRuleInternal(
|
||||
RenderingRuleProperty::createOutputStringProperty("attrStringValue"));
|
||||
|
||||
// order - no sense to make it float
|
||||
R_ORDER = registerRuleInternal(RenderingRuleProperty::createOutputIntProperty("order"));
|
||||
R_OBJECT_TYPE = registerRuleInternal(RenderingRuleProperty::createOutputIntProperty("objectType"));
|
||||
R_SHADOW_LEVEL = registerRuleInternal(RenderingRuleProperty::createOutputIntProperty("shadowLevel"));
|
||||
|
||||
// text properties
|
||||
R_TEXT_WRAP_WIDTH = registerRuleInternal(RenderingRuleProperty::createOutputIntProperty("textWrapWidth"));
|
||||
R_TEXT_DY = registerRuleInternal(RenderingRuleProperty::createOutputIntProperty("textDy"));
|
||||
R_TEXT_HALO_RADIUS = registerRuleInternal(RenderingRuleProperty::createOutputIntProperty("textHaloRadius"));
|
||||
R_TEXT_SIZE = registerRuleInternal(RenderingRuleProperty::createOutputIntProperty("textSize"));
|
||||
R_TEXT_ORDER = registerRuleInternal(RenderingRuleProperty::createOutputIntProperty("textOrder"));
|
||||
R_TEXT_MIN_DISTANCE = registerRuleInternal(RenderingRuleProperty::createOutputIntProperty("textMinDistance"));
|
||||
R_TEXT_SHIELD = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("textShield"));
|
||||
|
||||
R_TEXT_COLOR = registerRuleInternal(RenderingRuleProperty::createOutputColorProperty("textColor"));
|
||||
R_TEXT_BOLD = registerRuleInternal(RenderingRuleProperty::createOutputBooleanProperty("textBold"));
|
||||
R_TEXT_ON_PATH = registerRuleInternal(RenderingRuleProperty::createOutputBooleanProperty("textOnPath"));
|
||||
|
||||
// point
|
||||
R_ICON = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("icon"));
|
||||
|
||||
// polygon/way
|
||||
R_COLOR = registerRuleInternal(RenderingRuleProperty::createOutputColorProperty("color"));
|
||||
R_COLOR_2 = registerRuleInternal(RenderingRuleProperty::createOutputColorProperty("color_2"));
|
||||
R_COLOR_3 = registerRuleInternal(RenderingRuleProperty::createOutputColorProperty("color_3"));
|
||||
R_COLOR_0 = registerRuleInternal(RenderingRuleProperty::createOutputColorProperty("color_0"));
|
||||
R_COLOR__1 = registerRuleInternal(RenderingRuleProperty::createOutputColorProperty("color__1"));
|
||||
R_STROKE_WIDTH = registerRuleInternal(RenderingRuleProperty::createOutputFloatProperty("strokeWidth"));
|
||||
R_STROKE_WIDTH_2 = registerRuleInternal(RenderingRuleProperty::createOutputFloatProperty("strokeWidth_2"));
|
||||
R_STROKE_WIDTH_3 = registerRuleInternal(RenderingRuleProperty::createOutputFloatProperty("strokeWidth_3"));
|
||||
R_STROKE_WIDTH_0 = registerRuleInternal(RenderingRuleProperty::createOutputFloatProperty("strokeWidth_0"));
|
||||
R_STROKE_WIDTH__1 = registerRuleInternal(RenderingRuleProperty::createOutputFloatProperty("strokeWidth__1"));
|
||||
|
||||
R_PATH_EFFECT = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("pathEffect"));
|
||||
R_PATH_EFFECT_2 = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("pathEffect_2"));
|
||||
R_PATH_EFFECT_3 = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("pathEffect_3"));
|
||||
R_PATH_EFFECT_0 = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("pathEffect_0"));
|
||||
R_PATH_EFFECT__1 = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("pathEffect__1"));
|
||||
R_CAP = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("cap"));
|
||||
R_CAP_2 = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("cap_2"));
|
||||
R_CAP_3 = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("cap_3"));
|
||||
R_CAP_0 = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("cap_0"));
|
||||
R_CAP__1 = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("cap__1"));
|
||||
|
||||
R_SHADER = registerRuleInternal(RenderingRuleProperty::createOutputStringProperty("shader"));
|
||||
R_SHADOW_COLOR = registerRuleInternal(RenderingRuleProperty::createOutputColorProperty("shadowColor"));
|
||||
R_SHADOW_RADIUS = registerRuleInternal(RenderingRuleProperty::createOutputIntProperty("shadowRadius"));
|
||||
}
|
||||
|
||||
};
|
||||
static string A_DEFAULT_COLOR="defaultColor";
|
||||
static string A_SHADOW_RENDERING="shadowRendering";
|
||||
|
||||
class RenderingRulesStorage
|
||||
{
|
||||
|
||||
private:
|
||||
friend class RenderingRulesHandler;
|
||||
UNORDERED(map)<std::string, int> dictionaryMap;
|
||||
std::vector<std::string> dictionary;
|
||||
const static int SHIFT_TAG_VAL = 16;
|
||||
// TODO make private
|
||||
public:
|
||||
const static int SIZE_STATES = 7;
|
||||
UNORDERED(map)<int, RenderingRule*>* tagValueGlobalRules;
|
||||
map<std::string, RenderingRule*> renderingAttributes;
|
||||
map<std::string, std::string> renderingConstants;
|
||||
std::vector<RenderingRule*> childRules;
|
||||
public:
|
||||
RenderingRulesStorageProperties PROPS;
|
||||
// No rules for multipolygon !!!
|
||||
const static int MULTI_POLYGON_TYPE = 0;
|
||||
|
||||
const static int POINT_RULES = 1;
|
||||
const static int LINE_RULES = 2;
|
||||
const static int POLYGON_RULES = 3;
|
||||
const static int TEXT_RULES = 4;
|
||||
const static int ORDER_RULES = 5;
|
||||
RenderingRulesStorage(const void* storage, bool createDefProperties = true) : storageId(storage),
|
||||
PROPS(createDefProperties) {
|
||||
tagValueGlobalRules = new UNORDERED(map)<int, RenderingRule*>[SIZE_STATES];
|
||||
if(createDefProperties) {
|
||||
getDictionaryValue("");
|
||||
}
|
||||
}
|
||||
|
||||
~RenderingRulesStorage() {
|
||||
for (std::vector<RenderingRule*>::iterator rr = childRules.begin(); rr != childRules.end(); rr++) {
|
||||
delete *rr;
|
||||
}
|
||||
delete[] tagValueGlobalRules;
|
||||
}
|
||||
const void* storageId;
|
||||
|
||||
RenderingRule* getRule(int state, int itag, int ivalue);
|
||||
|
||||
void registerGlobalRule(RenderingRule* rr, int state);
|
||||
|
||||
int registerString(string d) {
|
||||
int res;
|
||||
dictionaryMap[d] = res = dictionary.size();
|
||||
dictionary.push_back(d);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline std::string getDictionaryValue(int i) {
|
||||
if (i < 0) {
|
||||
return std::string();
|
||||
}
|
||||
return dictionary.at(i);
|
||||
}
|
||||
|
||||
inline int getDictionaryValue(std::string s) {
|
||||
UNORDERED(map)<std::string, int>::iterator it = dictionaryMap.find(s);
|
||||
if(it == dictionaryMap.end()) {
|
||||
return registerString(s);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void parseRulesFromXmlInputStream(const char* filename, RenderingRulesStorageResolver* resolver);
|
||||
|
||||
RenderingRule* getRenderingAttributeRule(string attribute) {
|
||||
return renderingAttributes[attribute];
|
||||
}
|
||||
|
||||
inline string getStringValue(int i) {
|
||||
return dictionary[i];
|
||||
}
|
||||
|
||||
void printDebug(int state);
|
||||
|
||||
private:
|
||||
RenderingRule* createTagValueRootWrapperRule(int tagValueKey, RenderingRule* previous);
|
||||
|
||||
|
||||
inline string getValueString(int tagValueKey) {
|
||||
return getStringValue(tagValueKey & ((1 << SHIFT_TAG_VAL) - 1));
|
||||
}
|
||||
|
||||
inline string getTagString(int tagValueKey) {
|
||||
return getStringValue(tagValueKey >> SHIFT_TAG_VAL);
|
||||
}
|
||||
|
||||
inline int getTagValueKey(string tag, string value) {
|
||||
int itag = getDictionaryValue(tag);
|
||||
int ivalue = getDictionaryValue(value);
|
||||
return (itag << SHIFT_TAG_VAL) | ivalue;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class RenderingRuleSearchRequest
|
||||
{
|
||||
private :
|
||||
RenderingRulesStorageProperties* PROPS;
|
||||
vector<int> values;
|
||||
vector<float> fvalues;
|
||||
vector<int> savedValues;
|
||||
vector<float> savedFvalues;
|
||||
bool searchResult;
|
||||
MapDataObject* obj;
|
||||
|
||||
bool searchInternal(int state, int tagKey, int valueKey, bool loadOutput);
|
||||
bool visitRule(RenderingRule* rule, bool loadOutput);
|
||||
public:
|
||||
RenderingRulesStorage* storage;
|
||||
|
||||
RenderingRuleSearchRequest(RenderingRulesStorage* storage);
|
||||
|
||||
~RenderingRuleSearchRequest();
|
||||
|
||||
int getIntPropertyValue(RenderingRuleProperty* prop);
|
||||
|
||||
int getIntPropertyValue(RenderingRuleProperty* prop, int def);
|
||||
|
||||
std::string getStringPropertyValue(RenderingRuleProperty* prop);
|
||||
|
||||
float getFloatPropertyValue(RenderingRuleProperty* prop);
|
||||
|
||||
void setStringFilter(RenderingRuleProperty* p, std::string filter);
|
||||
|
||||
void setIntFilter(RenderingRuleProperty* p, int filter);
|
||||
|
||||
void clearIntvalue(RenderingRuleProperty* p);
|
||||
|
||||
void setBooleanFilter(RenderingRuleProperty* p, bool filter);
|
||||
|
||||
RenderingRulesStorageProperties* props();
|
||||
|
||||
bool searchRule(int state);
|
||||
|
||||
bool search(int state, bool loadOutput);
|
||||
|
||||
void clearState();
|
||||
|
||||
void saveState();
|
||||
|
||||
void setInitialTagValueZoom(std::string tag, std::string value, int zoom, MapDataObject* obj);
|
||||
|
||||
void setTagValueZoomLayer(std::string tag, std::string val, int zoom, int layer, MapDataObject* obj);
|
||||
|
||||
void externalInitialize(int* values, float* fvalues, int* savedValues, float* savedFvalues);
|
||||
|
||||
void printDebugResult();
|
||||
|
||||
void externalInitialize(vector<int>& vs, vector<float>& fvs, vector<int>& sVs, vector<float>& sFvs);
|
||||
|
||||
bool isSpecified(RenderingRuleProperty* p);
|
||||
|
||||
bool searchRenderingAttribute(string attribute);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
class BasePathRenderingRulesStorageResolver : public RenderingRulesStorageResolver {
|
||||
public:
|
||||
string path;
|
||||
BasePathRenderingRulesStorageResolver(string path) : path(path) {
|
||||
|
||||
}
|
||||
virtual RenderingRulesStorage* resolve(string name, RenderingRulesStorageResolver* ref) {
|
||||
string file = path;
|
||||
file += name;
|
||||
file+=".render.xml";
|
||||
RenderingRulesStorage* st = new RenderingRulesStorage(file.c_str());
|
||||
st->parseRulesFromXmlInputStream(file.c_str(), this);
|
||||
return st;
|
||||
}
|
||||
virtual ~BasePathRenderingRulesStorageResolver() {}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,822 +0,0 @@
|
|||
#include "osmand_log.h"
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <time.h>
|
||||
|
||||
#include <SkTypes.h>
|
||||
#include <SkBitmap.h>
|
||||
#include <SkCanvas.h>
|
||||
#include <SkColorFilter.h>
|
||||
#include <SkShader.h>
|
||||
#include <SkBitmapProcShader.h>
|
||||
#include <SkPathEffect.h>
|
||||
#include <SkBlurDrawLooper.h>
|
||||
#include <SkDashPathEffect.h>
|
||||
#include <SkPaint.h>
|
||||
#include <SkPath.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "renderRules.h"
|
||||
#include "binaryRead.h"
|
||||
#include "textdraw.cpp"
|
||||
#include "mapObjects.h"
|
||||
#include "rendering.h"
|
||||
|
||||
const int MAX_V = 75;
|
||||
|
||||
struct MapDataObjectPrimitive {
|
||||
MapDataObject* obj;
|
||||
int typeInd;
|
||||
float order;
|
||||
int objectType;
|
||||
};
|
||||
|
||||
|
||||
void calcPoint(std::pair<int, int> c, RenderingContext* rc)
|
||||
{
|
||||
rc->pointCount++;
|
||||
|
||||
float tx = c.first/ (rc->tileDivisor);
|
||||
float ty = c.second / (rc->tileDivisor);
|
||||
|
||||
float dTileX = tx - rc->getLeft();
|
||||
float dTileY = ty - rc->getTop();
|
||||
rc->calcX = rc->cosRotateTileSize * dTileX - rc->sinRotateTileSize * dTileY;
|
||||
rc->calcY = rc->sinRotateTileSize * dTileX + rc->cosRotateTileSize * dTileY;
|
||||
|
||||
if (rc->calcX >= 0 && rc->calcX < rc->getWidth()&& rc->calcY >= 0 && rc->calcY < rc->getHeight())
|
||||
rc->pointInsideCount++;
|
||||
}
|
||||
|
||||
|
||||
UNORDERED(map)<std::string, SkPathEffect*> pathEffects;
|
||||
SkPathEffect* getDashEffect(std::string input)
|
||||
{
|
||||
if(pathEffects.find(input) != pathEffects.end())
|
||||
return pathEffects[input];
|
||||
|
||||
const char* chars = input.c_str();
|
||||
int i = 0;
|
||||
char fval[10];
|
||||
int flength = 0;
|
||||
float primFloats[20];
|
||||
int floatLen = 0;
|
||||
for(;;i++)
|
||||
{
|
||||
if(chars[i] == 0)
|
||||
{
|
||||
if(flength > 0) { fval[flength] = 0;
|
||||
primFloats[floatLen++] = atof(fval); flength = 0;}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(chars[i] != '_')
|
||||
{
|
||||
// suppose it is a character
|
||||
fval[flength++] = chars[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(flength > 0)
|
||||
{
|
||||
fval[flength] = 0;
|
||||
primFloats[floatLen++] = atof(fval); flength = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SkPathEffect* r = new SkDashPathEffect(primFloats, floatLen, 0);
|
||||
pathEffects[input] = r;
|
||||
return r;
|
||||
}
|
||||
|
||||
int updatePaint(RenderingRuleSearchRequest* req, SkPaint* paint, int ind, int area, RenderingContext* rc)
|
||||
{
|
||||
RenderingRuleProperty* rColor;
|
||||
RenderingRuleProperty* rStrokeW;
|
||||
RenderingRuleProperty* rCap;
|
||||
RenderingRuleProperty* rPathEff;
|
||||
if (ind == 0)
|
||||
{
|
||||
rColor = req->props()->R_COLOR;
|
||||
rStrokeW = req->props()->R_STROKE_WIDTH;
|
||||
rCap = req->props()->R_CAP;
|
||||
rPathEff = req->props()->R_PATH_EFFECT;
|
||||
}
|
||||
else if (ind == 1)
|
||||
{
|
||||
rColor = req->props()->R_COLOR_2;
|
||||
rStrokeW = req->props()->R_STROKE_WIDTH_2;
|
||||
rCap = req->props()->R_CAP_2;
|
||||
rPathEff = req->props()->R_PATH_EFFECT_2;
|
||||
}
|
||||
else if (ind == -1)
|
||||
{
|
||||
rColor = req->props()->R_COLOR_0;
|
||||
rStrokeW = req->props()->R_STROKE_WIDTH_0;
|
||||
rCap = req->props()->R_CAP_0;
|
||||
rPathEff = req->props()->R_PATH_EFFECT_0;
|
||||
}
|
||||
else if (ind == -2)
|
||||
{
|
||||
rColor = req->props()->R_COLOR__1;
|
||||
rStrokeW = req->props()->R_STROKE_WIDTH__1;
|
||||
rCap = req->props()->R_CAP__1;
|
||||
rPathEff = req->props()->R_PATH_EFFECT__1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rColor = req->props()->R_COLOR_3;
|
||||
rStrokeW = req->props()->R_STROKE_WIDTH_3;
|
||||
rCap = req->props()->R_CAP_3;
|
||||
rPathEff = req->props()->R_PATH_EFFECT_3;
|
||||
}
|
||||
|
||||
if (area)
|
||||
{
|
||||
paint->setColorFilter(NULL);
|
||||
paint->setShader(NULL);
|
||||
paint->setLooper(NULL);
|
||||
paint->setStyle(SkPaint::kStrokeAndFill_Style);
|
||||
paint->setStrokeWidth(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
float stroke = req->getFloatPropertyValue(rStrokeW);
|
||||
if (!(stroke > 0))
|
||||
return 0;
|
||||
paint->setColorFilter(NULL);
|
||||
paint->setShader(NULL);
|
||||
paint->setLooper(NULL);
|
||||
|
||||
paint->setStyle(SkPaint::kStroke_Style);
|
||||
paint->setStrokeWidth(stroke);
|
||||
std::string cap = req->getStringPropertyValue(rCap);
|
||||
std::string pathEff = req->getStringPropertyValue(rPathEff);
|
||||
|
||||
if (cap == "BUTT" || cap == "")
|
||||
paint->setStrokeCap(SkPaint::kButt_Cap);
|
||||
else if (cap == "ROUND")
|
||||
paint->setStrokeCap(SkPaint::kRound_Cap);
|
||||
else if (cap == "SQUARE")
|
||||
paint->setStrokeCap(SkPaint::kSquare_Cap);
|
||||
else
|
||||
paint->setStrokeCap(SkPaint::kButt_Cap);
|
||||
|
||||
if (pathEff.size() > 0)
|
||||
{
|
||||
SkPathEffect* p = getDashEffect(pathEff);
|
||||
paint->setPathEffect(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
paint->setPathEffect(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int color = req->getIntPropertyValue(rColor);
|
||||
paint->setColor(color);
|
||||
|
||||
if (ind == 0)
|
||||
{
|
||||
std::string shader = req->getStringPropertyValue(req->props()->R_SHADER);
|
||||
if (shader.size() > 0)
|
||||
{
|
||||
SkBitmap* bmp = getCachedBitmap(rc, shader);
|
||||
if (bmp != NULL)
|
||||
paint->setShader(new SkBitmapProcShader(*bmp, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode))->unref();
|
||||
}
|
||||
}
|
||||
|
||||
// do not check shadow color here
|
||||
if (rc->getShadowRenderingMode() == 1 && ind == 0)
|
||||
{
|
||||
int shadowColor = req->getIntPropertyValue(req->props()->R_SHADOW_COLOR);
|
||||
int shadowLayer = req->getIntPropertyValue(req->props()->R_SHADOW_RADIUS);
|
||||
if (shadowColor == 0) {
|
||||
shadowColor = rc->getShadowRenderingColor();
|
||||
}
|
||||
if (shadowColor == 0)
|
||||
shadowLayer = 0;
|
||||
|
||||
if (shadowLayer > 0)
|
||||
paint->setLooper(new SkBlurDrawLooper(shadowLayer, 0, 0, shadowColor))->unref();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void renderText(MapDataObject* obj, RenderingRuleSearchRequest* req, RenderingContext* rc, std::string tag,
|
||||
std::string value, float xText, float yText, SkPath* path) {
|
||||
UNORDERED(map)<std::string, std::string>::iterator it = obj->objectNames.begin();
|
||||
while (it != obj->objectNames.end()) {
|
||||
if (it->second.length() > 0) {
|
||||
std::string name = it->second;
|
||||
name =rc->getTranslatedString(name);
|
||||
name =rc->getReshapedString(name);
|
||||
req->setInitialTagValueZoom(tag, value, rc->getZoom(), obj);
|
||||
req->setIntFilter(req->props()->R_TEXT_LENGTH, name.length());
|
||||
std::string tagName = it->first == "name" ? "" : it->first;
|
||||
req->setStringFilter(req->props()->R_NAME_TAG, tagName);
|
||||
if (req->searchRule(RenderingRulesStorage::TEXT_RULES)
|
||||
&& req->getIntPropertyValue(req->props()->R_TEXT_SIZE) > 0) {
|
||||
TextDrawInfo* info = new TextDrawInfo(name);
|
||||
info->drawOnPath = (path != NULL) && (req->getIntPropertyValue(req->props()->R_TEXT_ON_PATH, 0) > 0);
|
||||
if (path != NULL)
|
||||
info->path = new SkPath(*path);
|
||||
|
||||
fillTextProperties(info, req, xText, yText);
|
||||
rc->textToDraw.push_back(info);
|
||||
}
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void drawPolylineShadow(SkCanvas* cv, SkPaint* paint, RenderingContext* rc, SkPath* path, int shadowColor, int shadowRadius)
|
||||
{
|
||||
// blurred shadows
|
||||
if (rc->getShadowRenderingMode() == 2 && shadowRadius > 0) {
|
||||
// simply draw shadow? difference from option 3 ?
|
||||
// paint->setColor(0xffffffff);
|
||||
paint->setLooper(new SkBlurDrawLooper(shadowRadius, 0, 0, shadowColor))->unref();
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(*path, *paint));
|
||||
}
|
||||
|
||||
// option shadow = 3 with solid border
|
||||
if (rc->getShadowRenderingMode() == 3 && shadowRadius > 0) {
|
||||
paint->setLooper(NULL);
|
||||
paint->setStrokeWidth(paint->getStrokeWidth() + shadowRadius * 2);
|
||||
// paint->setColor(0xffbababa);
|
||||
paint->setColorFilter(SkColorFilter::CreateModeFilter(shadowColor, SkXfermode::kSrcIn_Mode))->unref();
|
||||
// paint->setColor(shadowColor);
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(*path, *paint));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<SkPaint> oneWayPaints;
|
||||
std::vector<SkPaint> reverseWayPaints;
|
||||
SkPaint* oneWayPaint(){
|
||||
SkPaint* oneWay = new SkPaint;
|
||||
oneWay->setStyle(SkPaint::kStroke_Style);
|
||||
oneWay->setColor(0xff6c70d5);
|
||||
oneWay->setAntiAlias(true);
|
||||
return oneWay;
|
||||
}
|
||||
void drawOneWayPaints(RenderingContext* rc, SkCanvas* cv, SkPath* p, int oneway) {
|
||||
if (oneWayPaints.size() == 0) {
|
||||
const float intervals_oneway[4][4] = {
|
||||
{0, 12, 10, 152},
|
||||
{0, 12, 9, 153},
|
||||
{0, 18, 2, 154},
|
||||
{0, 18, 1, 155}
|
||||
};
|
||||
SkPathEffect* arrowDashEffect1 = new SkDashPathEffect(intervals_oneway[0], 4, 0);
|
||||
SkPathEffect* arrowDashEffect2 = new SkDashPathEffect(intervals_oneway[1], 4, 1);
|
||||
SkPathEffect* arrowDashEffect3 = new SkDashPathEffect(intervals_oneway[2], 4, 1);
|
||||
SkPathEffect* arrowDashEffect4 = new SkDashPathEffect(intervals_oneway[3], 4, 1);
|
||||
|
||||
SkPaint* p = oneWayPaint();
|
||||
p->setStrokeWidth(1);
|
||||
p->setPathEffect(arrowDashEffect1)->unref();
|
||||
oneWayPaints.push_back(*p);
|
||||
delete p;
|
||||
|
||||
p = oneWayPaint();
|
||||
p->setStrokeWidth(2);
|
||||
p->setPathEffect(arrowDashEffect2)->unref();
|
||||
oneWayPaints.push_back(*p);
|
||||
delete p;
|
||||
|
||||
p = oneWayPaint();
|
||||
p->setStrokeWidth(3);
|
||||
p->setPathEffect(arrowDashEffect3)->unref();
|
||||
oneWayPaints.push_back(*p);
|
||||
delete p;
|
||||
|
||||
p = oneWayPaint();
|
||||
p->setStrokeWidth(4);
|
||||
p->setPathEffect(arrowDashEffect4)->unref();
|
||||
oneWayPaints.push_back(*p);
|
||||
delete p;
|
||||
}
|
||||
if (reverseWayPaints.size() == 0) {
|
||||
const float intervals_reverse[4][4] = {
|
||||
{0, 12, 10, 152},
|
||||
{0, 13, 9, 152},
|
||||
{0, 14, 2, 158},
|
||||
{0, 15, 1, 158}
|
||||
};
|
||||
SkPathEffect* arrowDashEffect1 = new SkDashPathEffect(intervals_reverse[0], 4, 0);
|
||||
SkPathEffect* arrowDashEffect2 = new SkDashPathEffect(intervals_reverse[1], 4, 1);
|
||||
SkPathEffect* arrowDashEffect3 = new SkDashPathEffect(intervals_reverse[2], 4, 1);
|
||||
SkPathEffect* arrowDashEffect4 = new SkDashPathEffect(intervals_reverse[3], 4, 1);
|
||||
SkPaint* p = oneWayPaint();
|
||||
p->setStrokeWidth(1);
|
||||
p->setPathEffect(arrowDashEffect1)->unref();
|
||||
reverseWayPaints.push_back(*p);
|
||||
delete p;
|
||||
|
||||
p = oneWayPaint();
|
||||
p->setStrokeWidth(2);
|
||||
p->setPathEffect(arrowDashEffect2)->unref();
|
||||
reverseWayPaints.push_back(*p);
|
||||
delete p;
|
||||
|
||||
p = oneWayPaint();
|
||||
p->setStrokeWidth(3);
|
||||
p->setPathEffect(arrowDashEffect3)->unref();
|
||||
reverseWayPaints.push_back(*p);
|
||||
delete p;
|
||||
|
||||
p = oneWayPaint();
|
||||
p->setStrokeWidth(4);
|
||||
p->setPathEffect(arrowDashEffect4)->unref();
|
||||
reverseWayPaints.push_back(*p);
|
||||
delete p;
|
||||
}
|
||||
if (oneway > 0) {
|
||||
for (size_t i = 0; i < oneWayPaints.size(); i++) {
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(*p, oneWayPaints.at(i)));
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < reverseWayPaints.size(); i++) {
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(*p, reverseWayPaints.at(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void drawPolyline(MapDataObject* mObj, RenderingRuleSearchRequest* req, SkCanvas* cv, SkPaint* paint,
|
||||
RenderingContext* rc, tag_value pair, int layer, int drawOnlyShadow) {
|
||||
size_t length = mObj->points.size();
|
||||
if (length < 2) {
|
||||
return;
|
||||
}
|
||||
std::string tag = pair.first;
|
||||
std::string value = pair.second;
|
||||
|
||||
req->setInitialTagValueZoom(tag, value, rc->getZoom(), mObj);
|
||||
req->setIntFilter(req->props()->R_LAYER, layer);
|
||||
bool rendered = req->searchRule(2);
|
||||
if (!rendered || !updatePaint(req, paint, 0, 0, rc)) {
|
||||
return;
|
||||
}
|
||||
int shadowColor = req->getIntPropertyValue(req->props()->R_SHADOW_COLOR);
|
||||
int shadowRadius = req->getIntPropertyValue(req->props()->R_SHADOW_RADIUS);
|
||||
if(drawOnlyShadow && shadowRadius == 0) {
|
||||
return;
|
||||
}
|
||||
if(shadowColor == 0) {
|
||||
shadowColor = rc->getShadowRenderingColor();
|
||||
}
|
||||
int oneway = 0;
|
||||
if (rc->getZoom() >= 16 && pair.first == "highway") {
|
||||
if (mObj->containsAdditional("oneway", "yes")) {
|
||||
oneway = 1;
|
||||
} else if (mObj->containsAdditional("oneway", "-1")) {
|
||||
oneway = -1;
|
||||
}
|
||||
}
|
||||
|
||||
rc->visible++;
|
||||
SkPath path;
|
||||
int i = 0;
|
||||
SkPoint middlePoint;
|
||||
int middle = length / 2;
|
||||
float prevx;
|
||||
float prevy;
|
||||
bool intersect = false;
|
||||
int prevCross = 0;
|
||||
for (; i < length; i++) {
|
||||
calcPoint(mObj->points.at(i), rc);
|
||||
if (i == 0) {
|
||||
path.moveTo(rc->calcX, rc->calcY);
|
||||
} else {
|
||||
if (i == middle) {
|
||||
middlePoint.set(rc->calcX, rc->calcY);
|
||||
}
|
||||
path.lineTo(rc->calcX, rc->calcY);
|
||||
}
|
||||
if (!intersect) {
|
||||
if (rc->calcX >= 0 && rc->calcY >= 0 && rc->calcX < rc->getWidth() && rc->calcY < rc->getHeight()) {
|
||||
intersect = true;
|
||||
} else {
|
||||
int cross = 0;
|
||||
cross |= (rc->calcX < 0 ? 1 : 0);
|
||||
cross |= (rc->calcX > rc->getWidth() ? 2 : 0);
|
||||
cross |= (rc->calcY < 0 ? 4 : 0);
|
||||
cross |= (rc->calcY > rc->getHeight() ? 8 : 0);
|
||||
if(i > 0) {
|
||||
if((prevCross & cross) == 0) {
|
||||
intersect = true;
|
||||
}
|
||||
}
|
||||
prevCross = cross;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!intersect) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
if (drawOnlyShadow) {
|
||||
drawPolylineShadow(cv, paint, rc, &path, shadowColor, shadowRadius);
|
||||
} else {
|
||||
if (updatePaint(req, paint, -2, 0, rc)) {
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
|
||||
}
|
||||
if (updatePaint(req, paint, -1, 0, rc)) {
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
|
||||
}
|
||||
if (updatePaint(req, paint, 0, 0, rc)) {
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
|
||||
}
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
|
||||
if (updatePaint(req, paint, 1, 0, rc)) {
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
|
||||
}
|
||||
if (updatePaint(req, paint, 2, 0, rc)) {
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
|
||||
}
|
||||
if (oneway && !drawOnlyShadow) {
|
||||
drawOneWayPaints(rc, cv, &path, oneway);
|
||||
}
|
||||
if (!drawOnlyShadow) {
|
||||
renderText(mObj, req, rc, pair.first, pair.second, middlePoint.fX, middlePoint.fY, &path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void drawPolygon(MapDataObject* mObj, RenderingRuleSearchRequest* req, SkCanvas* cv, SkPaint* paint,
|
||||
RenderingContext* rc, tag_value pair) {
|
||||
size_t length = mObj->points.size();
|
||||
if (length <= 2) {
|
||||
return;
|
||||
}
|
||||
std::string tag = pair.first;
|
||||
std::string value = pair.second;
|
||||
|
||||
req->setInitialTagValueZoom(tag, value, rc->getZoom(), mObj);
|
||||
bool rendered = req->searchRule(3);
|
||||
|
||||
float xText = 0;
|
||||
float yText = 0;
|
||||
if (!rendered || !updatePaint(req, paint, 0, 1, rc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rc->visible++;
|
||||
SkPath path;
|
||||
int i = 0;
|
||||
bool containsPoint = false;
|
||||
int bounds = 0;
|
||||
for (; i < length; i++) {
|
||||
calcPoint(mObj->points.at(i), rc);
|
||||
if (i == 0) {
|
||||
path.moveTo(rc->calcX, rc->calcY);
|
||||
} else {
|
||||
path.lineTo(rc->calcX, rc->calcY);
|
||||
}
|
||||
float tx = rc->calcX;
|
||||
if (tx < 0) {
|
||||
tx = 0;
|
||||
}
|
||||
if (tx > rc->getWidth()) {
|
||||
tx = rc->getWidth();
|
||||
}
|
||||
float ty = rc->calcY;
|
||||
if (ty < 0) {
|
||||
ty = 0;
|
||||
}
|
||||
if (ty > rc->getHeight()) {
|
||||
ty = rc->getHeight();
|
||||
}
|
||||
xText += tx;
|
||||
yText += ty;
|
||||
if (!containsPoint) {
|
||||
if (rc->calcX >= 0 && rc->calcY >= 0 && rc->calcX < rc->getWidth() && rc->calcY < rc->getHeight()) {
|
||||
containsPoint = true;
|
||||
}
|
||||
bounds |= (rc->calcX < 0 ? 1 : 0);
|
||||
bounds |= (rc->calcX >= rc->getWidth() ? 2 : 0);
|
||||
bounds |= (rc->calcY < 0 ? 4 : 0);
|
||||
bounds |= (rc->calcY >= rc->getHeight() ? 8 : 0);
|
||||
}
|
||||
}
|
||||
xText /= length;
|
||||
yText /= length;
|
||||
if(!containsPoint){
|
||||
if(bounds == 15) {
|
||||
xText = rc->getWidth() / 2;
|
||||
yText = rc->getHeight() / 2;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::vector<coordinates> polygonInnerCoordinates = mObj->polygonInnerCoordinates;
|
||||
if (polygonInnerCoordinates.size() > 0) {
|
||||
path.setFillType(SkPath::kEvenOdd_FillType);
|
||||
for (int j = 0; j < polygonInnerCoordinates.size(); j++) {
|
||||
coordinates cs = polygonInnerCoordinates.at(j);
|
||||
for (int i = 0; i < cs.size(); i++) {
|
||||
calcPoint(cs[i], rc);
|
||||
if (i == 0) {
|
||||
path.moveTo(rc->calcX, rc->calcY);
|
||||
} else {
|
||||
path.lineTo(rc->calcX, rc->calcY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
|
||||
if (updatePaint(req, paint, 1, 0, rc)) {
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawPath(path, *paint));
|
||||
}
|
||||
|
||||
renderText(mObj, req, rc, pair.first, pair.second, xText, yText, NULL);
|
||||
}
|
||||
|
||||
void drawPoint(MapDataObject* mObj, RenderingRuleSearchRequest* req, SkCanvas* cv, SkPaint* paint,
|
||||
RenderingContext* rc, std::pair<std::string, std::string> pair, int renderTxt)
|
||||
{
|
||||
std::string tag = pair.first;
|
||||
std::string value = pair.second;
|
||||
|
||||
req->setInitialTagValueZoom(tag, value, rc->getZoom(), mObj);
|
||||
req->searchRule(1);
|
||||
std::string resId = req->getStringPropertyValue(req-> props()-> R_ICON);
|
||||
SkBitmap* bmp = getCachedBitmap(rc, resId);
|
||||
|
||||
if (!bmp && !renderText)
|
||||
return;
|
||||
|
||||
size_t length = mObj->points.size();
|
||||
rc->visible++;
|
||||
float px = 0;
|
||||
float py = 0;
|
||||
int i = 0;
|
||||
for (; i < length; i++) {
|
||||
calcPoint(mObj->points.at(i), rc);
|
||||
px += rc->calcX;
|
||||
py += rc->calcY;
|
||||
}
|
||||
if (length > 1) {
|
||||
px /= length;
|
||||
py /= length;
|
||||
}
|
||||
|
||||
if (bmp != NULL) {
|
||||
IconDrawInfo ico;
|
||||
ico.x = px;
|
||||
ico.y = py;
|
||||
ico.bmp = bmp;
|
||||
rc->iconsToDraw.push_back(ico);
|
||||
}
|
||||
if (renderTxt) {
|
||||
renderText(mObj, req, rc, pair.first, pair.second, px, py, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void drawObject(RenderingContext* rc, SkCanvas* cv, RenderingRuleSearchRequest* req,
|
||||
SkPaint* paint, vector<MapDataObjectPrimitive>& array, int objOrder) {
|
||||
|
||||
double polygonLimit = 100;
|
||||
float orderToSwitch = 0;
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
rc->allObjects++;
|
||||
MapDataObject* mObj = array[i].obj;
|
||||
tag_value pair = mObj->types.at(array[i].typeInd);
|
||||
if (objOrder == 0) {
|
||||
if (array[i].order < rc->polygonMinSizeToDisplay) {
|
||||
return;
|
||||
}
|
||||
// polygon
|
||||
drawPolygon(mObj, req, cv, paint, rc, pair);
|
||||
} else if (objOrder == 1 || objOrder == 2) {
|
||||
drawPolyline(mObj, req, cv, paint, rc, pair, mObj->getSimpleLayer(), objOrder == 1);
|
||||
} else if (objOrder == 3) {
|
||||
drawPoint(mObj, req, cv, paint, rc, pair, array[i].typeInd == 0);
|
||||
}
|
||||
if (i % 25 == 0 && rc->interrupted()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void drawIconsOverCanvas(RenderingContext* rc, SkCanvas* canvas)
|
||||
{
|
||||
int skewConstant = (int) rc->getDensityValue(16);
|
||||
int iconsW = rc -> getWidth() / skewConstant;
|
||||
int iconsH = rc -> getHeight() / skewConstant;
|
||||
int len = (iconsW * iconsH) / 32;
|
||||
int alreadyDrawnIcons[len];
|
||||
memset(alreadyDrawnIcons, 0, sizeof(int)*len);
|
||||
size_t ji = 0;
|
||||
SkPaint p;
|
||||
p.setStyle(SkPaint::kStroke_Style);
|
||||
p.setFilterBitmap(true);
|
||||
for(;ji< rc->iconsToDraw.size(); ji++)
|
||||
{
|
||||
IconDrawInfo icon = rc->iconsToDraw.at(ji);
|
||||
if (icon.y >= 0 && icon.y < rc->getHeight() && icon.x >= 0 && icon.x < rc->getWidth() && icon.bmp != NULL) {
|
||||
int z = (((int) icon.x / skewConstant) + ((int) icon.y / skewConstant) * iconsW);
|
||||
int i = z / 32;
|
||||
if (i >= len) {
|
||||
continue;
|
||||
}
|
||||
int ind = alreadyDrawnIcons[i];
|
||||
int b = z % 32;
|
||||
// check bit b if it is set
|
||||
if (((ind >> b) & 1) == 0) {
|
||||
alreadyDrawnIcons[i] = ind | (1 << b);
|
||||
SkBitmap* ico = icon.bmp;
|
||||
float left = icon.x - rc->getDensityValue(ico->width() / 2);
|
||||
float top = icon.y - rc->getDensityValue(ico->height() / 2);
|
||||
SkRect r = SkRect::MakeXYWH(left, top, rc->getDensityValue(ico->width()),
|
||||
rc->getDensityValue(ico->height()));
|
||||
PROFILE_NATIVE_OPERATION(rc, canvas->drawBitmapRect(*ico, (SkIRect*) NULL, r, &p));
|
||||
}
|
||||
}
|
||||
if (rc->interrupted()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double polygonArea(MapDataObject* obj, float mult) {
|
||||
double area = 0.;
|
||||
int j = obj->points.size() - 1;
|
||||
for (int i = 0; i < obj->points.size(); i++) {
|
||||
int_pair x = obj->points[i] ;
|
||||
int_pair y = obj->points[j];
|
||||
area += (y.first + ((float) x.first) )* (y.second- ((float)x.second));
|
||||
j = i;
|
||||
}
|
||||
return std::abs(area) * mult * mult * .5;
|
||||
}
|
||||
|
||||
void filterLinesByDensity(RenderingContext* rc, std::vector<MapDataObjectPrimitive>& linesResArray,
|
||||
std::vector<MapDataObjectPrimitive>& linesArray) {
|
||||
int roadsLimit = rc->roadsDensityLimitPerTile;
|
||||
int densityZ = rc->roadDensityZoomTile;
|
||||
if(densityZ == 0 || roadsLimit == 0) {
|
||||
linesResArray = linesArray;
|
||||
return;
|
||||
}
|
||||
linesResArray.reserve(linesArray.size());
|
||||
UNORDERED(map)<int64_t, pair<int, int> > densityMap;
|
||||
for (int i = linesArray.size() - 1; i >= 0; i--) {
|
||||
bool accept = true;
|
||||
int o = linesArray[i].order;
|
||||
MapDataObject* line = linesArray[i].obj;
|
||||
tag_value& ts = line->types[linesArray[i].typeInd];
|
||||
if (ts.first == "highway") {
|
||||
accept = false;
|
||||
int64_t prev = 0;
|
||||
for (int k = 0; k < line->points.size(); k++) {
|
||||
int dz = rc->getZoom() + densityZ;
|
||||
int64_t x = (line->points[k].first) >> (31 - dz);
|
||||
int64_t y = (line->points[k].second) >> (31 - dz);
|
||||
int64_t tl = (x << dz) + y;
|
||||
if (prev != tl) {
|
||||
prev = tl;
|
||||
pair<int, int>& p = densityMap[tl];
|
||||
if (p.first < roadsLimit/* && p.second > o */) {
|
||||
accept = true;
|
||||
p.first++;
|
||||
p.second = o;
|
||||
densityMap[tl] = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(accept) {
|
||||
linesResArray.push_back(linesArray[i]);
|
||||
}
|
||||
}
|
||||
reverse(linesResArray.begin(), linesResArray.end());
|
||||
}
|
||||
bool sortByOrder(const MapDataObjectPrimitive& i,const MapDataObjectPrimitive& j) {
|
||||
if( i.order == j.order) {
|
||||
if(i.typeInd == j.typeInd) {
|
||||
return i.obj->points.size() < j.obj->points.size() ;
|
||||
}
|
||||
return i.typeInd < j.typeInd;
|
||||
}
|
||||
return (i.order<j.order); }
|
||||
bool sortPolygonsOrder(const MapDataObjectPrimitive& i,const MapDataObjectPrimitive& j) {
|
||||
if( i.order == j.order) return i.typeInd < j.typeInd;
|
||||
return (i.order>j.order); }
|
||||
|
||||
void sortObjectsByProperOrder(std::vector <MapDataObject* > mapDataObjects,
|
||||
RenderingRuleSearchRequest* req, RenderingContext* rc,
|
||||
std::vector<MapDataObjectPrimitive>& polygonsArray, std::vector<MapDataObjectPrimitive>& pointsArray,
|
||||
std::vector<MapDataObjectPrimitive>& linesResArray) {
|
||||
if (req != NULL) {
|
||||
std::vector<MapDataObjectPrimitive> linesArray;
|
||||
req->clearState();
|
||||
const int size = mapDataObjects.size();
|
||||
float mult = 1. / getPowZoom(max(31 - (rc->getZoom() + 8), 0));
|
||||
int i = 0;
|
||||
for (; i < size; i++) {
|
||||
uint32_t sh = i << 8;
|
||||
MapDataObject* mobj = mapDataObjects[i];
|
||||
size_t sizeTypes = mobj->types.size();
|
||||
size_t j = 0;
|
||||
for (; j < sizeTypes; j++) {
|
||||
int layer = mobj->getSimpleLayer();
|
||||
tag_value pair = mobj->types[j];
|
||||
req->setTagValueZoomLayer(pair.first, pair.second, rc->getZoom(), layer, mobj);
|
||||
req->setIntFilter(req->props()->R_AREA, mobj->area);
|
||||
req->setIntFilter(req->props()->R_POINT, mobj->points.size() == 1);
|
||||
req->setIntFilter(req->props()->R_CYCLE, mobj->cycle());
|
||||
if (req->searchRule(RenderingRulesStorage::ORDER_RULES)) {
|
||||
int objectType = req->getIntPropertyValue(req->props()->R_OBJECT_TYPE);
|
||||
int order = req->getIntPropertyValue(req->props()->R_ORDER);
|
||||
MapDataObjectPrimitive mapObj;
|
||||
mapObj.objectType = objectType;
|
||||
mapObj.order = order;
|
||||
mapObj.typeInd = j;
|
||||
mapObj.obj = mobj;
|
||||
// polygon
|
||||
if(objectType == 3) {
|
||||
MapDataObjectPrimitive pointObj = mapObj;
|
||||
pointObj.objectType = 1;
|
||||
mapObj.order = polygonArea(mobj, mult);
|
||||
if(mapObj.order > MAX_V) {
|
||||
polygonsArray.push_back(mapObj);
|
||||
pointsArray.push_back(pointObj);
|
||||
}
|
||||
} else if(objectType == 1) {
|
||||
pointsArray.push_back(mapObj);
|
||||
} else {
|
||||
linesArray.push_back(mapObj);
|
||||
}
|
||||
if (req->getIntPropertyValue(req->props()->R_SHADOW_LEVEL) > 0) {
|
||||
rc->shadowLevelMin = std::min(rc->shadowLevelMin, order);
|
||||
rc->shadowLevelMax = std::max(rc->shadowLevelMax, order);
|
||||
req->clearIntvalue(req->props()->R_SHADOW_LEVEL);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
sort(polygonsArray.begin(), polygonsArray.end(), sortPolygonsOrder);
|
||||
sort(pointsArray.begin(), pointsArray.end(), sortByOrder);
|
||||
sort(linesArray.begin(), linesArray.end(), sortByOrder);
|
||||
filterLinesByDensity(rc, linesResArray, linesArray);
|
||||
}
|
||||
}
|
||||
|
||||
void doRendering(std::vector <MapDataObject* > mapDataObjects, SkCanvas* canvas,
|
||||
RenderingRuleSearchRequest* req,
|
||||
RenderingContext* rc) {
|
||||
rc->nativeOperations.start();
|
||||
SkPaint* paint = new SkPaint;
|
||||
paint->setAntiAlias(true);
|
||||
|
||||
std::vector<MapDataObjectPrimitive> polygonsArray;
|
||||
std::vector<MapDataObjectPrimitive> pointsArray;
|
||||
std::vector<MapDataObjectPrimitive> linesArray;
|
||||
sortObjectsByProperOrder(mapDataObjects, req, rc, polygonsArray, pointsArray, linesArray);
|
||||
rc->lastRenderedKey = 0;
|
||||
|
||||
drawObject(rc, canvas, req, paint, polygonsArray, 0);
|
||||
rc->lastRenderedKey = 5;
|
||||
if (rc->getShadowRenderingMode() > 1) {
|
||||
drawObject(rc, canvas, req, paint, linesArray, 1);
|
||||
}
|
||||
rc->lastRenderedKey = 40;
|
||||
drawObject(rc, canvas, req, paint, linesArray, 2);
|
||||
rc->lastRenderedKey = 60;
|
||||
|
||||
drawObject(rc, canvas, req, paint, pointsArray, 3);
|
||||
rc->lastRenderedKey = 125;
|
||||
|
||||
drawIconsOverCanvas(rc, canvas);
|
||||
|
||||
rc->textRendering.start();
|
||||
drawTextOverCanvas(rc, canvas);
|
||||
rc->textRendering.pause();
|
||||
|
||||
delete paint;
|
||||
rc->nativeOperations.pause();
|
||||
osmand_log_print(LOG_INFO, "Native ok (rendering %d, text %d ms) \n (%d points, %d points inside, %d of %d objects visible)\n",
|
||||
rc->nativeOperations.getElapsedTime(), rc->textRendering.getElapsedTime(),
|
||||
rc->pointCount, rc->pointInsideCount, rc->visible, rc->allObjects);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef _OSMAND_RENDERING_H
|
||||
#define _OSMAND_RENDERING_H
|
||||
|
||||
#include "common.h"
|
||||
#include "renderRules.h"
|
||||
#include <vector>
|
||||
#include <SkCanvas.h>
|
||||
|
||||
|
||||
void doRendering(std::vector <MapDataObject* > mapDataObjects, SkCanvas* canvas,
|
||||
RenderingRuleSearchRequest* req, RenderingContext* rc);
|
||||
|
||||
|
||||
#endif
|
|
@ -1,39 +0,0 @@
|
|||
// http://stackoverflow.com/questions/7792011/alternative-to-boostshared-ptr-in-an-embedded-environment
|
||||
template<class T>
|
||||
class my_shared_ptr
|
||||
{
|
||||
template<class U>
|
||||
friend class my_shared_ptr;
|
||||
public:
|
||||
my_shared_ptr() :p(), c() {}
|
||||
explicit my_shared_ptr(T* s) :p(s), c(new unsigned(1)) {}
|
||||
|
||||
my_shared_ptr(const my_shared_ptr& s) :p(s.p), c(s.c) { if(c) ++*c; }
|
||||
|
||||
my_shared_ptr& operator=(const my_shared_ptr& s)
|
||||
{ if(this!=&s) { clear(); p=s.p; c=s.c; if(c) ++*c; } return *this; }
|
||||
|
||||
template<class U>
|
||||
my_shared_ptr(const my_shared_ptr<U>& s) :p(s.p), c(s.c) { if(c) ++*c; }
|
||||
|
||||
~my_shared_ptr() { clear(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
if(c)
|
||||
{
|
||||
if(*c==1) delete p;
|
||||
if(!--*c) delete c;
|
||||
}
|
||||
c=0; p=0;
|
||||
}
|
||||
|
||||
T* get() const { return (c)? p: 0; }
|
||||
T* operator->() const { return get(); }
|
||||
T& operator*() const { return *get(); }
|
||||
|
||||
private:
|
||||
T* p;
|
||||
unsigned* c;
|
||||
};
|
||||
|
|
@ -1,574 +0,0 @@
|
|||
#include <vector>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include "SkTypes.h"
|
||||
#include "SkTypeface.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkPath.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "renderRules.h"
|
||||
//#include "utf8.cpp"
|
||||
#include "utf8/unchecked.h"
|
||||
|
||||
|
||||
template <typename T> class quad_tree {
|
||||
private :
|
||||
struct node {
|
||||
typedef std::vector<T> cont_t;
|
||||
cont_t data;
|
||||
node* children[4];
|
||||
SkRect bounds;
|
||||
|
||||
node(SkRect& b) : bounds(b) {
|
||||
memset(children,0,4*sizeof(node*));
|
||||
}
|
||||
|
||||
~node() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (children[i] != NULL) {
|
||||
delete children[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
typedef typename node::cont_t cont_t;
|
||||
typedef typename cont_t::iterator node_data_iterator;
|
||||
double ratio;
|
||||
unsigned int max_depth;
|
||||
node root;
|
||||
public:
|
||||
quad_tree(SkRect& r, int depth=8, double ratio = 0.55) : ratio(ratio), max_depth(depth), root(r) {
|
||||
}
|
||||
|
||||
void insert(T data, SkRect& box)
|
||||
{
|
||||
unsigned int depth=0;
|
||||
do_insert_data(data, box, &root, depth);
|
||||
}
|
||||
|
||||
void query_in_box(SkRect& box, std::vector<T>& result)
|
||||
{
|
||||
result.clear();
|
||||
query_node(box, result, &root);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void query_node(SkRect& box, std::vector<T> & result, node* node) const {
|
||||
if (node) {
|
||||
if (SkRect::Intersects(box, node->bounds)) {
|
||||
node_data_iterator i = node->data.begin();
|
||||
node_data_iterator end = node->data.end();
|
||||
while (i != end) {
|
||||
result.push_back(*i);
|
||||
++i;
|
||||
}
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
query_node(box, result, node->children[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void do_insert_data(T data, SkRect& box, node * n, unsigned int& depth)
|
||||
{
|
||||
if (++depth >= max_depth) {
|
||||
n->data.push_back(data);
|
||||
} else {
|
||||
SkRect& node_extent = n->bounds;
|
||||
SkRect ext[4];
|
||||
split_box(node_extent, ext);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (ext[i].contains(box)) {
|
||||
if (!n->children[i]) {
|
||||
n->children[i] = new node(ext[i]);
|
||||
}
|
||||
do_insert_data(data, box, n->children[i], depth);
|
||||
return;
|
||||
}
|
||||
}
|
||||
n->data.push_back(data);
|
||||
}
|
||||
}
|
||||
void split_box(SkRect& node_extent,SkRect * ext)
|
||||
{
|
||||
//coord2d c=node_extent.center();
|
||||
|
||||
float width=node_extent.width();
|
||||
float height=node_extent.height();
|
||||
|
||||
float lox=node_extent.fLeft;
|
||||
float loy=node_extent.fTop;
|
||||
float hix=node_extent.fRight;
|
||||
float hiy=node_extent.fBottom;
|
||||
|
||||
ext[0]=SkRect::MakeLTRB(lox,loy,lox + width * ratio,loy + height * ratio);
|
||||
ext[1]=SkRect::MakeLTRB(hix - width * ratio,loy,hix,loy + height * ratio);
|
||||
ext[2]=SkRect::MakeLTRB(lox,hiy - height*ratio,lox + width * ratio,hiy);
|
||||
ext[3]=SkRect::MakeLTRB(hix - width * ratio,hiy - height*ratio,hix,hiy);
|
||||
}
|
||||
};
|
||||
|
||||
inline float sqr(float a){
|
||||
return a*a;
|
||||
}
|
||||
|
||||
inline float absFloat(float a){
|
||||
return a > 0 ? a : -a;
|
||||
}
|
||||
|
||||
|
||||
void fillTextProperties(TextDrawInfo* info, RenderingRuleSearchRequest* render, float cx, float cy) {
|
||||
info->centerX = cx;
|
||||
info->centerY = cy + render->getIntPropertyValue(render->props()->R_TEXT_DY, 0);
|
||||
// used only for draw on path where centerY doesn't play role
|
||||
info->vOffset = render->getIntPropertyValue(render->props()->R_TEXT_DY, 0);
|
||||
info->textColor = render->getIntPropertyValue(render->props()->R_TEXT_COLOR);
|
||||
if (info->textColor == 0) {
|
||||
info->textColor = 0xff000000;
|
||||
}
|
||||
info->textSize = render->getIntPropertyValue(render->props()->R_TEXT_SIZE);
|
||||
info->textShadow = render->getIntPropertyValue(render->props()->R_TEXT_HALO_RADIUS, 0);
|
||||
info->textWrap = render->getIntPropertyValue(render->props()->R_TEXT_WRAP_WIDTH, 0);
|
||||
info->bold = render->getIntPropertyValue(render->props()->R_TEXT_BOLD, 0) > 0;
|
||||
info->minDistance = render->getIntPropertyValue(render->props()->R_TEXT_MIN_DISTANCE, 0);
|
||||
info->shieldRes = render->getStringPropertyValue(render->props()->R_TEXT_SHIELD);
|
||||
info->textOrder = render->getIntPropertyValue(render->props()->R_TEXT_ORDER, 100);
|
||||
}
|
||||
|
||||
bool isLetterOrDigit(char c)
|
||||
{
|
||||
return c != ' ';
|
||||
}
|
||||
|
||||
void drawTextOnCanvas(SkCanvas* cv, const char* text, uint16_t len, float centerX, float centerY, SkPaint& paintText,
|
||||
float textShadow) {
|
||||
if (textShadow > 0) {
|
||||
int c = paintText.getColor();
|
||||
paintText.setStyle(SkPaint::kStroke_Style);
|
||||
paintText.setColor(-1); // white
|
||||
paintText.setStrokeWidth(2 + textShadow);
|
||||
cv->drawText(text, len, centerX, centerY, paintText);
|
||||
// reset
|
||||
paintText.setStrokeWidth(2);
|
||||
paintText.setStyle(SkPaint::kFill_Style);
|
||||
paintText.setColor(c);
|
||||
}
|
||||
cv->drawText(text, len, centerX, centerY, paintText);
|
||||
}
|
||||
|
||||
|
||||
int nextWord(uint8_t* s, int* charRead) {
|
||||
uint8_t* init = s;
|
||||
while((*s) != 0) {
|
||||
uint32_t tp = utf8::unchecked::next(s);
|
||||
(*charRead) ++;
|
||||
if(tp == ' ' || tp == '\t') {
|
||||
return (s - init);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
void drawWrappedText(RenderingContext* rc, SkCanvas* cv, TextDrawInfo* text, float textSize, SkPaint& paintText) {
|
||||
if(text->textWrap == 0) {
|
||||
// set maximum for all text
|
||||
text->textWrap = 40;
|
||||
}
|
||||
|
||||
if(text->text.length() > text->textWrap) {
|
||||
const char* c_str = text->text.c_str();
|
||||
|
||||
int end = text->text.length();
|
||||
int line = 0;
|
||||
int pos = 0;
|
||||
int start = 0;
|
||||
while(start < end) {
|
||||
const char* p_str = c_str;
|
||||
int lastSpace = -1;
|
||||
int prevPos = -1;
|
||||
int charRead = 0;
|
||||
do {
|
||||
int lastSpace = nextWord((uint8_t*)p_str, &charRead);
|
||||
if (lastSpace == -1) {
|
||||
pos = end;
|
||||
} else {
|
||||
p_str += lastSpace;
|
||||
if(pos != start && charRead >= text->textWrap){
|
||||
break;
|
||||
}
|
||||
pos += lastSpace;
|
||||
}
|
||||
} while(pos < end && charRead < text->textWrap);
|
||||
|
||||
PROFILE_NATIVE_OPERATION(rc, drawTextOnCanvas(cv, c_str, pos - start , text->centerX, text->centerY + line * (textSize + 2), paintText, text->textShadow));
|
||||
c_str += (pos - start);
|
||||
start = pos;
|
||||
line++;
|
||||
}
|
||||
} else {
|
||||
PROFILE_NATIVE_OPERATION(rc, drawTextOnCanvas(cv, text->text.data(), text->text.length(), text->centerX, text->centerY, paintText, text->textShadow));
|
||||
}
|
||||
}
|
||||
|
||||
bool calculatePathToRotate(RenderingContext* rc, TextDrawInfo* p) {
|
||||
if(p->path == NULL) {
|
||||
return true;
|
||||
}
|
||||
int len = p->path->countPoints();
|
||||
SkPoint points[len];
|
||||
p->path->getPoints(points, len);
|
||||
|
||||
|
||||
bool inverse = false;
|
||||
float roadLength = 0;
|
||||
bool prevInside = false;
|
||||
float visibleRoadLength = 0;
|
||||
float textw = p->bounds.width();
|
||||
int i;
|
||||
int startVisible = 0;
|
||||
std::vector<float> distances;
|
||||
distances.resize(roadLength, 0);
|
||||
|
||||
float normalTextLen = 1.5 * textw;
|
||||
for (i = 0; i < len; i++) {
|
||||
bool inside = points[i].fX >= 0 && points[i].fX <= rc->getWidth() &&
|
||||
points[i].fY >= 0 && points[i].fY <= rc->getHeight();
|
||||
if (i > 0) {
|
||||
float d = sqrt(
|
||||
(points[i].fX - points[i - 1].fX) * (points[i].fX - points[i - 1].fX)
|
||||
+ (points[i].fY - points[i - 1].fY) * (points[i].fY - points[i - 1].fY));
|
||||
distances.push_back(d);
|
||||
roadLength += d;
|
||||
if(inside) {
|
||||
visibleRoadLength += d;
|
||||
if(!prevInside) {
|
||||
startVisible = i - 1;
|
||||
}
|
||||
} else if(prevInside) {
|
||||
if(visibleRoadLength >= normalTextLen) {
|
||||
break;
|
||||
}
|
||||
visibleRoadLength = 0;
|
||||
}
|
||||
|
||||
}
|
||||
prevInside = inside;
|
||||
}
|
||||
if (textw >= roadLength) {
|
||||
return false;
|
||||
}
|
||||
int startInd = 0;
|
||||
int endInd = len;
|
||||
|
||||
if(textw < visibleRoadLength && i - startVisible > 1) {
|
||||
startInd = startVisible;
|
||||
endInd = i;
|
||||
// display long road name in center
|
||||
if (visibleRoadLength > 3 * textw) {
|
||||
bool ch ;
|
||||
do {
|
||||
ch = false;
|
||||
if(endInd - startInd > 2 && visibleRoadLength - distances[startInd] > normalTextLen){
|
||||
visibleRoadLength -= distances.at(startInd);
|
||||
startInd++;
|
||||
ch = true;
|
||||
}
|
||||
if(endInd - startInd > 2 && visibleRoadLength - distances[endInd - 2] > normalTextLen){
|
||||
visibleRoadLength -= distances.at(endInd - 2);
|
||||
endInd--;
|
||||
ch = true;
|
||||
}
|
||||
} while(ch);
|
||||
}
|
||||
}
|
||||
|
||||
if (!p->drawOnPath) {
|
||||
int middle = startInd + 1 + (endInd - startInd - 1) / 2;
|
||||
|
||||
float px = 0;
|
||||
float py = 0;
|
||||
for (i = startInd; i < endInd; i++) {
|
||||
px += points[i].fX ;
|
||||
py += points[i].fY;
|
||||
}
|
||||
px /= (endInd - startInd);
|
||||
py /= (endInd - startInd);
|
||||
float cx = 0;
|
||||
float cy = 0;
|
||||
float cd = -1;
|
||||
for (i = startInd + 1; i < endInd; i++) {
|
||||
float fd = sqr(px - points[i].fX) + sqr(py - points[i].fY);
|
||||
if (cd < 0 || fd < cd) {
|
||||
cx = points[i].fX;
|
||||
cy = points[i].fY;
|
||||
cd = fd;
|
||||
}
|
||||
}
|
||||
p->centerX = cx;
|
||||
p->centerY = cy;
|
||||
p->pathRotate = atan2(py, px);
|
||||
p->vOffset += p->textSize / 2 - 1;
|
||||
p->hOffset = 0;
|
||||
} else {
|
||||
// shrink path to display more text
|
||||
|
||||
if (startInd > 0 || endInd < len) {
|
||||
// find subpath
|
||||
SkPath* path = new SkPath;
|
||||
for (int i = startInd; i < endInd; i++) {
|
||||
if (i == startInd) {
|
||||
path->moveTo(points[i].fX, points[i].fY);
|
||||
} else {
|
||||
path->lineTo(points[i].fX, points[i].fY);
|
||||
}
|
||||
}
|
||||
if (p->path != NULL) {
|
||||
delete p->path;
|
||||
}
|
||||
p->path = path;
|
||||
}
|
||||
// calculate vector of the road (px, py) to proper rotate it
|
||||
float px = 0;
|
||||
float py = 0;
|
||||
for (i = startInd + 1; i < endInd; i++) {
|
||||
px += points[i].fX - points[i - 1].fX;
|
||||
py += points[i].fY - points[i - 1].fY;
|
||||
}
|
||||
float scale = 0.5f;
|
||||
float plen = sqrt(px * px + py * py);
|
||||
// vector ox,oy orthogonal to px,py to measure height
|
||||
float ox = -py;
|
||||
float oy = px;
|
||||
if (plen > 0 ) {
|
||||
float rot = atan2(py, px);
|
||||
if (rot < 0)
|
||||
rot += M_PI * 2;
|
||||
if (rot > M_PI_2 && rot < 3 * M_PI_2) {
|
||||
rot += M_PI;
|
||||
inverse = true;
|
||||
ox = -ox;
|
||||
oy = -oy;
|
||||
}
|
||||
p->pathRotate = rot;
|
||||
ox *= (p->bounds.height() / plen) / 2;
|
||||
oy *= (p->bounds.height() / plen) / 2;
|
||||
}
|
||||
|
||||
p->centerX = points[startInd].fX + scale * px + ox;
|
||||
p->centerY = points[startInd].fY + scale * py + oy;
|
||||
p->vOffset += p->textSize / 2 - 1;
|
||||
p->hOffset = 0;
|
||||
|
||||
if (inverse) {
|
||||
SkPath* path = new SkPath;
|
||||
for (int i = endInd - 1; i >= startInd; i--) {
|
||||
if (i == (int) (endInd - 1)) {
|
||||
path->moveTo(points[i].fX, points[i].fY);
|
||||
} else {
|
||||
path->lineTo(points[i].fX, points[i].fY);
|
||||
}
|
||||
}
|
||||
if (p->path != NULL) {
|
||||
delete p->path;
|
||||
}
|
||||
p->path = path;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void drawTestBox(SkCanvas* cv, SkRect* r, float rot, SkPaint* paintIcon, std::string text, SkPaint* paintText)
|
||||
{
|
||||
cv->save();
|
||||
cv->translate(r->centerX(),r->centerY());
|
||||
cv->rotate(rot * 180 / M_PI);
|
||||
SkRect rs = SkRect::MakeLTRB(-r->width()/2, -r->height()/2,
|
||||
r->width()/2, r->height()/2);
|
||||
cv->drawRect(rs, *paintIcon);
|
||||
if (paintText != NULL) {
|
||||
cv->drawText(text.data(), text.length(), rs.centerX(), rs.centerY(),
|
||||
*paintText);
|
||||
}
|
||||
cv->restore();
|
||||
}
|
||||
|
||||
|
||||
bool intersects(SkRect tRect, float tRot, TextDrawInfo* s)
|
||||
{
|
||||
float sRot = s->pathRotate;
|
||||
if (absFloat(tRot) < M_PI / 15 && absFloat(sRot) < M_PI / 15) {
|
||||
return SkRect::Intersects(tRect, s->bounds);
|
||||
}
|
||||
float dist = sqrt(sqr(tRect.centerX() - s->bounds.centerX()) + sqr(tRect.centerY() - s->bounds.centerY()));
|
||||
if(dist < 3) {
|
||||
return true;
|
||||
}
|
||||
SkRect sRect = s->bounds;
|
||||
|
||||
// difference close to 90/270 degrees
|
||||
if(absFloat(cos(tRot-sRot)) < 0.3 ){
|
||||
// rotate one rectangle to 90 degrees
|
||||
tRot += M_PI_2;
|
||||
tRect = SkRect::MakeXYWH(tRect.centerX() - tRect.height() / 2, tRect.centerY() - tRect.width() / 2,
|
||||
tRect.height(), tRect.width());
|
||||
}
|
||||
|
||||
// determine difference close to 180/0 degrees
|
||||
if(absFloat(sin(tRot-sRot)) < 0.3){
|
||||
// rotate t box
|
||||
// (calculate offset for t center suppose we rotate around s center)
|
||||
float diff = atan2(tRect.centerY() - sRect.centerY(), tRect.centerX() - sRect.centerX());
|
||||
diff -= sRot;
|
||||
float left = sRect.centerX() + dist* cos(diff) - tRect.width()/2;
|
||||
float top = sRect.centerY() - dist* sin(diff) - tRect.height()/2;
|
||||
SkRect nRect = SkRect::MakeXYWH(left, top, tRect.width(), tRect.height());
|
||||
return SkRect::Intersects(nRect, sRect);
|
||||
}
|
||||
|
||||
// TODO other cases not covered
|
||||
return SkRect::Intersects(tRect, sRect);
|
||||
}
|
||||
|
||||
bool intersects(TextDrawInfo* t, TextDrawInfo* s) {
|
||||
return intersects(t->bounds, t->pathRotate, s);
|
||||
}
|
||||
inline float max(float a, float b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
vector<TextDrawInfo*> searchText;
|
||||
bool findTextIntersection(SkCanvas* cv, RenderingContext* rc, quad_tree<TextDrawInfo*>& boundIntersections, TextDrawInfo* text,
|
||||
SkPaint* paintText, SkPaint* paintIcon) {
|
||||
paintText->measureText(text->text.c_str(), text->text.length(), &text->bounds);
|
||||
// make wider
|
||||
text->bounds.inset(-rc->getDensityValue( 3), -rc->getDensityValue(10));
|
||||
|
||||
bool display = calculatePathToRotate(rc, text);
|
||||
if (!display) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(text->path == NULL) {
|
||||
text->bounds.offset(text->centerX, text->centerY);
|
||||
// shift to match alignment
|
||||
text->bounds.offset(-text->bounds.width()/2, 0);
|
||||
} else {
|
||||
text->bounds.offset(text->centerX - text->bounds.width()/2, text->centerY - text->bounds.height()/2);
|
||||
}
|
||||
|
||||
// for text purposes
|
||||
// drawTestBox(cv, &text->bounds, text->pathRotate, paintIcon, text->text, NULL/*paintText*/);
|
||||
boundIntersections.query_in_box(text->bounds, searchText);
|
||||
for (uint32_t i = 0; i < searchText.size(); i++) {
|
||||
TextDrawInfo* t = searchText.at(i);
|
||||
if (intersects(text, t)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(text->minDistance > 0) {
|
||||
SkRect boundsSearch = text->bounds;
|
||||
boundsSearch.inset(-rc->getDensityValue(max(5.0f, text->minDistance)), -rc->getDensityValue(15));
|
||||
boundIntersections.query_in_box(boundsSearch, searchText);
|
||||
// drawTestBox(cv, &boundsSearch, text->pathRotate, paintIcon, text->text, paintText);
|
||||
for (uint32_t i = 0; i < searchText.size(); i++) {
|
||||
TextDrawInfo* t = searchText.at(i);
|
||||
if (t->minDistance > 0 && t->text == text->text && intersects(boundsSearch, text->pathRotate, t)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boundIntersections.insert(text, text->bounds);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool textOrder(TextDrawInfo* text1, TextDrawInfo* text2) {
|
||||
return text1->textOrder < text2->textOrder;
|
||||
}
|
||||
|
||||
SkTypeface* serif = SkTypeface::CreateFromName("Droid Serif", SkTypeface::kNormal);
|
||||
void drawTextOverCanvas(RenderingContext* rc, SkCanvas* cv) {
|
||||
SkRect r = SkRect::MakeLTRB(0, 0, rc->getWidth(), rc->getHeight());
|
||||
r.inset(-100, -100);
|
||||
quad_tree<TextDrawInfo*> boundsIntersect(r, 4, 0.6);
|
||||
|
||||
SkPaint paintIcon;
|
||||
paintIcon.setStyle(SkPaint::kStroke_Style);
|
||||
paintIcon.setStrokeWidth(1);
|
||||
paintIcon.setColor(0xff000000);
|
||||
paintIcon.setFilterBitmap(true);
|
||||
SkPaint paintText;
|
||||
paintText.setStyle(SkPaint::kFill_Style);
|
||||
paintText.setStrokeWidth(1);
|
||||
paintText.setColor(0xff000000);
|
||||
paintText.setTextAlign(SkPaint::kCenter_Align);
|
||||
paintText.setTypeface(serif);
|
||||
paintText.setAntiAlias(true);
|
||||
SkPaint::FontMetrics fm;
|
||||
|
||||
// 1. Sort text using text order
|
||||
std::sort(rc->textToDraw.begin(), rc->textToDraw.end(), textOrder);
|
||||
for (uint32_t i = 0; i < rc->textToDraw.size(); i++) {
|
||||
TextDrawInfo* text = rc->textToDraw.at(i);
|
||||
if (text->text.length() > 0) {
|
||||
// sest text size before finding intersection (it is used there)
|
||||
float textSize = rc->getDensityValue(text->textSize);
|
||||
paintText.setTextSize(textSize);
|
||||
paintText.setFakeBoldText(text->bold);
|
||||
paintText.setColor(text->textColor);
|
||||
// align center y
|
||||
paintText.getFontMetrics(&fm);
|
||||
text->centerY += (-fm.fAscent);
|
||||
|
||||
// calculate if there is intersection
|
||||
bool intersects = findTextIntersection(cv, rc, boundsIntersect, text, &paintText, &paintIcon);
|
||||
if (!intersects) {
|
||||
if(rc->interrupted()){
|
||||
return;
|
||||
}
|
||||
if (text->drawOnPath && text->path != NULL) {
|
||||
if (text->textShadow > 0) {
|
||||
paintText.setColor(0xFFFFFFFF);
|
||||
paintText.setStyle(SkPaint::kStroke_Style);
|
||||
paintText.setStrokeWidth(2 + text->textShadow);
|
||||
rc->nativeOperations.pause();
|
||||
cv->drawTextOnPathHV(text->text.c_str(), text->text.length(), *text->path, text->hOffset,
|
||||
text->vOffset, paintText);
|
||||
rc->nativeOperations.start();
|
||||
// reset
|
||||
paintText.setStyle(SkPaint::kFill_Style);
|
||||
paintText.setStrokeWidth(2);
|
||||
paintText.setColor(text->textColor);
|
||||
}
|
||||
rc->nativeOperations.pause();
|
||||
cv->drawTextOnPathHV(text->text.c_str(), text->text.length(), *text->path, text->hOffset,
|
||||
text->vOffset, paintText);
|
||||
rc->nativeOperations.start();
|
||||
} else {
|
||||
if (text->shieldRes.length() > 0) {
|
||||
SkBitmap* ico = getCachedBitmap(rc, text->shieldRes);
|
||||
if (ico != NULL) {
|
||||
float left = text->centerX - rc->getDensityValue(ico->width() / 2) - 0.5f;
|
||||
float top = text->centerY - rc->getDensityValue(ico->height() / 2)
|
||||
- rc->getDensityValue(4.5f);
|
||||
SkRect r = SkRect::MakeXYWH(left, top, rc->getDensityValue(ico->width()),
|
||||
rc->getDensityValue(ico->height()));
|
||||
PROFILE_NATIVE_OPERATION(rc, cv->drawBitmapRect(*ico, (SkIRect*) NULL, r, &paintIcon));
|
||||
}
|
||||
}
|
||||
drawWrappedText(rc, cv, text, textSize, paintText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,329 +0,0 @@
|
|||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
|
||||
// You may need to change them to match your system.
|
||||
// These typedefs have the same names as ones from cstdint, or boost/cstdint
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
// Helper code - not intended to be directly called by the library users. May be changed at any time
|
||||
namespace internal
|
||||
{
|
||||
// Unicode constants
|
||||
// Leading (high) surrogates: 0xd800 - 0xdbff
|
||||
// Trailing (low) surrogates: 0xdc00 - 0xdfff
|
||||
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
|
||||
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
|
||||
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
|
||||
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
|
||||
const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
|
||||
const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
|
||||
|
||||
// Maximum valid value for a Unicode code point
|
||||
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
|
||||
|
||||
template<typename octet_type>
|
||||
inline uint8_t mask8(octet_type oc)
|
||||
{
|
||||
return static_cast<uint8_t>(0xff & oc);
|
||||
}
|
||||
template<typename u16_type>
|
||||
inline uint16_t mask16(u16_type oc)
|
||||
{
|
||||
return static_cast<uint16_t>(0xffff & oc);
|
||||
}
|
||||
template<typename octet_type>
|
||||
inline bool is_trail(octet_type oc)
|
||||
{
|
||||
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_lead_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_trail_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u32>
|
||||
inline bool is_code_point_valid(u32 cp)
|
||||
{
|
||||
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline typename std::iterator_traits<octet_iterator>::difference_type
|
||||
sequence_length(octet_iterator lead_it)
|
||||
{
|
||||
uint8_t lead = utf8::internal::mask8(*lead_it);
|
||||
if (lead < 0x80)
|
||||
return 1;
|
||||
else if ((lead >> 5) == 0x6)
|
||||
return 2;
|
||||
else if ((lead >> 4) == 0xe)
|
||||
return 3;
|
||||
else if ((lead >> 3) == 0x1e)
|
||||
return 4;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename octet_difference_type>
|
||||
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
|
||||
{
|
||||
if (cp < 0x80) {
|
||||
if (length != 1)
|
||||
return true;
|
||||
}
|
||||
else if (cp < 0x800) {
|
||||
if (length != 2)
|
||||
return true;
|
||||
}
|
||||
else if (cp < 0x10000) {
|
||||
if (length != 3)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
|
||||
|
||||
/// Helper for get_sequence_x
|
||||
template <typename octet_iterator>
|
||||
utf_error increase_safely(octet_iterator& it, octet_iterator end)
|
||||
{
|
||||
if (++it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
if (!utf8::internal::is_trail(*it))
|
||||
return INCOMPLETE_SEQUENCE;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
|
||||
|
||||
/// get_sequence_x functions decode utf-8 sequences of the length x
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (*it) & 0x3f;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (*it) & 0x3f;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
// Save the original value of it so we can go back in case of failure
|
||||
// Of course, it does not make much sense with i.e. stream iterators
|
||||
octet_iterator original_it = it;
|
||||
|
||||
uint32_t cp = 0;
|
||||
// Determine the sequence length based on the lead octet
|
||||
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
|
||||
const octet_difference_type length = utf8::internal::sequence_length(it);
|
||||
|
||||
// Get trail octets and calculate the code point
|
||||
utf_error err = UTF8_OK;
|
||||
switch (length) {
|
||||
case 0:
|
||||
return INVALID_LEAD;
|
||||
case 1:
|
||||
err = utf8::internal::get_sequence_1(it, end, cp);
|
||||
break;
|
||||
case 2:
|
||||
err = utf8::internal::get_sequence_2(it, end, cp);
|
||||
break;
|
||||
case 3:
|
||||
err = utf8::internal::get_sequence_3(it, end, cp);
|
||||
break;
|
||||
case 4:
|
||||
err = utf8::internal::get_sequence_4(it, end, cp);
|
||||
break;
|
||||
}
|
||||
|
||||
if (err == UTF8_OK) {
|
||||
// Decoding succeeded. Now, security checks...
|
||||
if (utf8::internal::is_code_point_valid(cp)) {
|
||||
if (!utf8::internal::is_overlong_sequence(cp, length)){
|
||||
// Passed! Return here.
|
||||
code_point = cp;
|
||||
++it;
|
||||
return UTF8_OK;
|
||||
}
|
||||
else
|
||||
err = OVERLONG_SEQUENCE;
|
||||
}
|
||||
else
|
||||
err = INVALID_CODE_POINT;
|
||||
}
|
||||
|
||||
// Failure branch - restore the original value of the iterator
|
||||
it = original_it;
|
||||
return err;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
|
||||
uint32_t ignored;
|
||||
return utf8::internal::validate_next(it, end, ignored);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// The library API - functions intended to be called by the users
|
||||
|
||||
// Byte order mark
|
||||
const uint8_t bom[] = {0xef, 0xbb, 0xbf};
|
||||
|
||||
template <typename octet_iterator>
|
||||
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
|
||||
{
|
||||
octet_iterator result = start;
|
||||
while (result != end) {
|
||||
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
|
||||
if (err_code != internal::UTF8_OK)
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline bool is_valid(octet_iterator start, octet_iterator end)
|
||||
{
|
||||
return (utf8::find_invalid(start, end) == end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
|
||||
{
|
||||
return (
|
||||
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
|
||||
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
|
||||
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
|
||||
);
|
||||
}
|
||||
|
||||
//Deprecated in release 2.3
|
||||
template <typename octet_iterator>
|
||||
inline bool is_bom (octet_iterator it)
|
||||
{
|
||||
return (
|
||||
(utf8::internal::mask8(*it++)) == bom[0] &&
|
||||
(utf8::internal::mask8(*it++)) == bom[1] &&
|
||||
(utf8::internal::mask8(*it)) == bom[2]
|
||||
);
|
||||
}
|
||||
} // namespace utf8
|
||||
|
||||
#endif // header guard
|
||||
|
||||
|
|
@ -1,228 +0,0 @@
|
|||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include "core.h"
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
namespace unchecked
|
||||
{
|
||||
template <typename octet_iterator>
|
||||
octet_iterator append(uint32_t cp, octet_iterator result)
|
||||
{
|
||||
if (cp < 0x80) // one octet
|
||||
*(result++) = static_cast<uint8_t>(cp);
|
||||
else if (cp < 0x800) { // two octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else if (cp < 0x10000) { // three octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else { // four octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t next(octet_iterator& it)
|
||||
{
|
||||
uint32_t cp = utf8::internal::mask8(*it);
|
||||
typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
|
||||
switch (length) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
it++;
|
||||
cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||
break;
|
||||
case 3:
|
||||
++it;
|
||||
cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||
++it;
|
||||
cp += (*it) & 0x3f;
|
||||
break;
|
||||
case 4:
|
||||
++it;
|
||||
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||
++it;
|
||||
cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||
++it;
|
||||
cp += (*it) & 0x3f;
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
return cp;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t peek_next(octet_iterator it)
|
||||
{
|
||||
return utf8::unchecked::next(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t prior(octet_iterator& it)
|
||||
{
|
||||
while (utf8::internal::is_trail(*(--it))) ;
|
||||
octet_iterator temp = it;
|
||||
return utf8::unchecked::next(temp);
|
||||
}
|
||||
|
||||
// Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
|
||||
template <typename octet_iterator>
|
||||
inline uint32_t previous(octet_iterator& it)
|
||||
{
|
||||
return utf8::unchecked::prior(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename distance_type>
|
||||
void advance (octet_iterator& it, distance_type n)
|
||||
{
|
||||
for (distance_type i = 0; i < n; ++i)
|
||||
utf8::unchecked::next(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
typename std::iterator_traits<octet_iterator>::difference_type
|
||||
distance (octet_iterator first, octet_iterator last)
|
||||
{
|
||||
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||
for (dist = 0; first < last; ++dist)
|
||||
utf8::unchecked::next(first);
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end) {
|
||||
uint32_t cp = utf8::internal::mask16(*start++);
|
||||
// Take care of surrogate pairs first
|
||||
if (utf8::internal::is_lead_surrogate(cp)) {
|
||||
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
|
||||
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
|
||||
}
|
||||
result = utf8::unchecked::append(cp, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
|
||||
{
|
||||
while (start < end) {
|
||||
uint32_t cp = utf8::unchecked::next(start);
|
||||
if (cp > 0xffff) { //make a surrogate pair
|
||||
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||
}
|
||||
else
|
||||
*result++ = static_cast<uint16_t>(cp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
result = utf8::unchecked::append(*(start++), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
|
||||
{
|
||||
while (start < end)
|
||||
(*result++) = utf8::unchecked::next(start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// The iterator class
|
||||
template <typename octet_iterator>
|
||||
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
|
||||
octet_iterator it;
|
||||
public:
|
||||
iterator () {};
|
||||
explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
|
||||
// the default "big three" are OK
|
||||
octet_iterator base () const { return it; }
|
||||
uint32_t operator * () const
|
||||
{
|
||||
octet_iterator temp = it;
|
||||
return utf8::unchecked::next(temp);
|
||||
}
|
||||
bool operator == (const iterator& rhs) const
|
||||
{
|
||||
return (it == rhs.it);
|
||||
}
|
||||
bool operator != (const iterator& rhs) const
|
||||
{
|
||||
return !(operator == (rhs));
|
||||
}
|
||||
iterator& operator ++ ()
|
||||
{
|
||||
::std::advance(it, utf8::internal::sequence_length(it));
|
||||
return *this;
|
||||
}
|
||||
iterator operator ++ (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
::std::advance(it, utf8::internal::sequence_length(it));
|
||||
return temp;
|
||||
}
|
||||
iterator& operator -- ()
|
||||
{
|
||||
utf8::unchecked::prior(it);
|
||||
return *this;
|
||||
}
|
||||
iterator operator -- (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::unchecked::prior(it);
|
||||
return temp;
|
||||
}
|
||||
}; // class iterator
|
||||
|
||||
} // namespace utf8::unchecked
|
||||
} // namespace utf8
|
||||
|
||||
|
||||
#endif // header guard
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/sh
|
||||
make && ./osmand_main -renderingOutputFile=/home/victor/1.png -zoom=11 -lt=12,8 -lbox=-80,22.5 \
|
||||
-renderingInputFile="/home/victor/projects/OsmAnd/data/osm-gen/Cuba2.obf" -renderingInputFile="/home/victor/projects/OsmAnd/data/osm-gen/basemap_2.obf" \
|
||||
-renderingStyleFile="/home/victor/projects/OsmAnd/git/DataExtractionOSM/src/net/osmand/render/default.render.xml" \
|
||||
-imagesBasePathFile="/home/victor/projects/OsmAnd/git/OsmAnd/res/drawable-mdpi/"
|
1
Osmand-kernel/png/.gitignore
vendored
1
Osmand-kernel/png/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
build-*
|
|
@ -1,40 +0,0 @@
|
|||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
include $(LOCAL_PATH)/Common.mk
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libz
|
||||
|
||||
ifneq ($(OSMAND_BUILDING_NEON_LIBRARY),true)
|
||||
LOCAL_MODULE := png
|
||||
else
|
||||
LOCAL_MODULE := png_neon
|
||||
endif
|
||||
ifneq ($(OSMAND_USE_PREBUILT),true)
|
||||
|
||||
common_CFLAGS := -fvisibility=hidden ## -fomit-frame-pointer
|
||||
|
||||
ifeq ($(HOST_OS),windows)
|
||||
ifeq ($(USE_MINGW),)
|
||||
# Case where we're building windows but not under linux (so it must be cygwin)
|
||||
# In this case, gcc cygwin doesn't recognize -fvisibility=hidden
|
||||
$(info libpng: Ignoring gcc flag $(common_CFLAGS) on Cygwin)
|
||||
common_CFLAGS :=
|
||||
endif
|
||||
endif
|
||||
|
||||
common_C_INCLUDES +=
|
||||
|
||||
common_COPY_HEADERS_TO := libpng
|
||||
common_COPY_HEADERS := png.h pngconf.h pngusr.h
|
||||
|
||||
LOCAL_CFLAGS += $(common_CFLAGS)
|
||||
LOCAL_C_INCLUDES += $(common_C_INCLUDES) \
|
||||
external/zlib
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
else
|
||||
LOCAL_SRC_FILES := \
|
||||
../lib/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
endif
|
|
@ -1,25 +0,0 @@
|
|||
OSMAND_PNG_LOC := ./png_library
|
||||
|
||||
OSMAND_PNG_ABS := $(LOCAL_PATH)/png_library
|
||||
LOCAL_SRC_FILES:= \
|
||||
$(OSMAND_PNG_LOC)/png.c \
|
||||
$(OSMAND_PNG_LOC)/pngerror.c \
|
||||
$(OSMAND_PNG_LOC)/pnggccrd.c \
|
||||
$(OSMAND_PNG_LOC)/pngget.c \
|
||||
$(OSMAND_PNG_LOC)/pngmem.c \
|
||||
$(OSMAND_PNG_LOC)/pngpread.c \
|
||||
$(OSMAND_PNG_LOC)/pngread.c \
|
||||
$(OSMAND_PNG_LOC)/pngrio.c \
|
||||
$(OSMAND_PNG_LOC)/pngrtran.c \
|
||||
$(OSMAND_PNG_LOC)/pngrutil.c \
|
||||
$(OSMAND_PNG_LOC)/pngset.c \
|
||||
$(OSMAND_PNG_LOC)/pngtrans.c \
|
||||
$(OSMAND_PNG_LOC)/pngvcrd.c \
|
||||
$(OSMAND_PNG_LOC)/pngwio.c \
|
||||
$(OSMAND_PNG_LOC)/pngwrite.c \
|
||||
$(OSMAND_PNG_LOC)/pngwtran.c \
|
||||
$(OSMAND_PNG_LOC)/pngwutil.c
|
||||
|
||||
LOCAL_C_INCLUDES +=
|
||||
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
# Include tools definitions
|
||||
include ../Makefile.vars
|
||||
|
||||
# Include project files
|
||||
LOCAL_PATH = .
|
||||
include Common.mk
|
||||
|
||||
# Set library name
|
||||
LIBNAME = $(LIBRARY_PREFIX)png
|
||||
LIBTYPE = $(STATICLIB_EXT)
|
||||
|
||||
# Finally, include generic rules
|
||||
include ../Makefile.rules
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 17b24482db9fb75020b91a9c17f2014beebc86ed
|
1
Osmand-kernel/protobuf/.gitignore
vendored
1
Osmand-kernel/protobuf/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
build-*
|
|
@ -1,27 +0,0 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
include $(LOCAL_PATH)/Common.mk
|
||||
|
||||
ifneq ($(OSMAND_BUILDING_NEON_LIBRARY),true)
|
||||
LOCAL_MODULE := proto
|
||||
else
|
||||
LOCAL_MODULE := proto_neon
|
||||
LOCAL_ARM_NEON := true
|
||||
endif
|
||||
|
||||
ifneq ($(OSMAND_USE_PREBUILT),true)
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_CPP_EXTENSION := .cc
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||
LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI
|
||||
LOCAL_LDLIBS := -llog
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
else
|
||||
LOCAL_SRC_FILES := \
|
||||
../lib/$(TARGET_ARCH_ABI)/lib$(LOCAL_MODULE).a
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
endif
|
|
@ -1,14 +0,0 @@
|
|||
CC_LITE_SRC_FILES := \
|
||||
google/protobuf/stubs/common.cc \
|
||||
google/protobuf/stubs/once.cc \
|
||||
google/protobuf/stubs/hash.cc \
|
||||
google/protobuf/extension_set.cc \
|
||||
google/protobuf/generated_message_util.cc \
|
||||
google/protobuf/message_lite.cc \
|
||||
google/protobuf/repeated_field.cc \
|
||||
google/protobuf/wire_format_lite.cc \
|
||||
google/protobuf/io/coded_stream.cc \
|
||||
google/protobuf/io/zero_copy_stream.cc \
|
||||
google/protobuf/io/zero_copy_stream_impl_lite.cc
|
||||
LOCAL_SRC_FILES := $(CC_LITE_SRC_FILES) \
|
||||
google/protobuf/io/zero_copy_stream_impl.cc
|
|
@ -1,16 +0,0 @@
|
|||
# Include tools definitions
|
||||
include ../Makefile.vars
|
||||
|
||||
# Include project files
|
||||
LOCAL_PATH = .
|
||||
include Common.mk
|
||||
|
||||
# Set library name
|
||||
LIBNAME = $(LIBRARY_PREFIX)proto
|
||||
LIBTYPE = $(STATICLIB_EXT)
|
||||
CXXFLAGS += -DGOOGLE_PROTOBUF_NO_RTTI
|
||||
LDFLAGS += -lpthread
|
||||
LOCAL_C_INCLUDES += .
|
||||
|
||||
# Finally, include generic rules
|
||||
include ../Makefile.rules
|
|
@ -1,192 +0,0 @@
|
|||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
#if defined(ANDROID)
|
||||
/* the namespace of hash_map/hash_set */
|
||||
#define HASH_NAMESPACE std
|
||||
|
||||
/* the name of <hash_set> */
|
||||
#define HASH_MAP_CLASS tr1::unordered_map
|
||||
|
||||
/* the location of <hash_map> */
|
||||
#define HASH_MAP_H <unordered_map>
|
||||
|
||||
/* the name of <hash_set> */
|
||||
#define HASH_SET_CLASS tr1::unordered_set
|
||||
|
||||
/* the location of <hash_set> */
|
||||
#define HASH_SET_H <unordered_set>
|
||||
|
||||
/* define if the compiler has hash_map */
|
||||
#define HAVE_HASH_MAP 1
|
||||
|
||||
/* define if the compiler has hash_set */
|
||||
#define HAVE_HASH_SET 1
|
||||
#elif defined(__APPLE__)
|
||||
/* the namespace of hash_map/hash_set */
|
||||
#define HASH_NAMESPACE std::tr1
|
||||
|
||||
/* the name of <hash_set> */
|
||||
#define HASH_MAP_CLASS unordered_map
|
||||
|
||||
/* the location of <hash_map> */
|
||||
#define HASH_MAP_H <tr1/unordered_map>
|
||||
|
||||
/* the name of <hash_set> */
|
||||
#define HASH_SET_CLASS unordered_set
|
||||
|
||||
/* the location of <hash_set> */
|
||||
#define HASH_SET_H <tr1/unordered_set>
|
||||
|
||||
/* define if the compiler has hash_map */
|
||||
#define HAVE_HASH_MAP 1
|
||||
|
||||
/* define if the compiler has hash_set */
|
||||
#define HAVE_HASH_SET 1
|
||||
#else
|
||||
/* the namespace of hash_map/hash_set */
|
||||
#define HASH_NAMESPACE std
|
||||
|
||||
/* the name of <hash_set> */
|
||||
#define HASH_MAP_CLASS unordered_map
|
||||
|
||||
/* the location of <hash_map> */
|
||||
#define HASH_MAP_H <unordered_map>
|
||||
|
||||
/* the name of <hash_set> */
|
||||
#define HASH_SET_CLASS unordered_set
|
||||
|
||||
/* the location of <hash_set> */
|
||||
#define HASH_SET_H <unordered_set>
|
||||
|
||||
/* define if the compiler has hash_map */
|
||||
#define HAVE_HASH_MAP 1
|
||||
|
||||
/* define if the compiler has hash_set */
|
||||
#define HAVE_HASH_SET 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `ftruncate' function. */
|
||||
#define HAVE_FTRUNCATE 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#define HAVE_MEMSET 1
|
||||
|
||||
/* Define to 1 if you have the `mkdir' function. */
|
||||
#define HAVE_MKDIR 1
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#define HAVE_PTHREAD 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#define HAVE_STRCHR 1
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#define HAVE_STRERROR 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the `strtol' function. */
|
||||
#define HAVE_STRTOL 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Enable classes using zlib compression. */
|
||||
#define HAVE_ZLIB 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "protobuf"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "protobuf@googlegroups.com"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "Protocol Buffers"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "Protocol Buffers 2.3.0"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "protobuf"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "2.3.0"
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
/* #undef PTHREAD_CREATE_JOINABLE */
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.3.0"
|
||||
|
||||
/* Define to 1 if on AIX 3.
|
||||
System headers sometimes define this.
|
||||
We just want to avoid a redefinition error message. */
|
||||
#ifndef _ALL_SOURCE
|
||||
/* # undef _ALL_SOURCE */
|
||||
#endif
|
||||
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
/* #undef _MINIX */
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */
|
||||
/* #undef _POSIX_1_SOURCE */
|
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */
|
||||
/* #undef _POSIX_SOURCE */
|
||||
|
||||
/* Enable extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# define __EXTENSIONS__ 1
|
||||
#endif
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# define _POSIX_PTHREAD_SEMANTICS 1
|
||||
#endif
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# define _TANDEM_SOURCE 1
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,433 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// The messages in this file describe the definitions found in .proto files.
|
||||
// A valid .proto file can be translated directly to a FileDescriptorProto
|
||||
// without any other information (e.g. without reading its imports).
|
||||
|
||||
|
||||
|
||||
package google.protobuf;
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "DescriptorProtos";
|
||||
|
||||
// descriptor.proto must be optimized for speed because reflection-based
|
||||
// algorithms don't work during bootstrapping.
|
||||
option optimize_for = SPEED;
|
||||
|
||||
// The protocol compiler can output a FileDescriptorSet containing the .proto
|
||||
// files it parses.
|
||||
message FileDescriptorSet {
|
||||
repeated FileDescriptorProto file = 1;
|
||||
}
|
||||
|
||||
// Describes a complete .proto file.
|
||||
message FileDescriptorProto {
|
||||
optional string name = 1; // file name, relative to root of source tree
|
||||
optional string package = 2; // e.g. "foo", "foo.bar", etc.
|
||||
|
||||
// Names of files imported by this file.
|
||||
repeated string dependency = 3;
|
||||
|
||||
// All top-level definitions in this file.
|
||||
repeated DescriptorProto message_type = 4;
|
||||
repeated EnumDescriptorProto enum_type = 5;
|
||||
repeated ServiceDescriptorProto service = 6;
|
||||
repeated FieldDescriptorProto extension = 7;
|
||||
|
||||
optional FileOptions options = 8;
|
||||
}
|
||||
|
||||
// Describes a message type.
|
||||
message DescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
repeated FieldDescriptorProto field = 2;
|
||||
repeated FieldDescriptorProto extension = 6;
|
||||
|
||||
repeated DescriptorProto nested_type = 3;
|
||||
repeated EnumDescriptorProto enum_type = 4;
|
||||
|
||||
message ExtensionRange {
|
||||
optional int32 start = 1;
|
||||
optional int32 end = 2;
|
||||
}
|
||||
repeated ExtensionRange extension_range = 5;
|
||||
|
||||
optional MessageOptions options = 7;
|
||||
}
|
||||
|
||||
// Describes a field within a message.
|
||||
message FieldDescriptorProto {
|
||||
enum Type {
|
||||
// 0 is reserved for errors.
|
||||
// Order is weird for historical reasons.
|
||||
TYPE_DOUBLE = 1;
|
||||
TYPE_FLOAT = 2;
|
||||
TYPE_INT64 = 3; // Not ZigZag encoded. Negative numbers
|
||||
// take 10 bytes. Use TYPE_SINT64 if negative
|
||||
// values are likely.
|
||||
TYPE_UINT64 = 4;
|
||||
TYPE_INT32 = 5; // Not ZigZag encoded. Negative numbers
|
||||
// take 10 bytes. Use TYPE_SINT32 if negative
|
||||
// values are likely.
|
||||
TYPE_FIXED64 = 6;
|
||||
TYPE_FIXED32 = 7;
|
||||
TYPE_BOOL = 8;
|
||||
TYPE_STRING = 9;
|
||||
TYPE_GROUP = 10; // Tag-delimited aggregate.
|
||||
TYPE_MESSAGE = 11; // Length-delimited aggregate.
|
||||
|
||||
// New in version 2.
|
||||
TYPE_BYTES = 12;
|
||||
TYPE_UINT32 = 13;
|
||||
TYPE_ENUM = 14;
|
||||
TYPE_SFIXED32 = 15;
|
||||
TYPE_SFIXED64 = 16;
|
||||
TYPE_SINT32 = 17; // Uses ZigZag encoding.
|
||||
TYPE_SINT64 = 18; // Uses ZigZag encoding.
|
||||
};
|
||||
|
||||
enum Label {
|
||||
// 0 is reserved for errors
|
||||
LABEL_OPTIONAL = 1;
|
||||
LABEL_REQUIRED = 2;
|
||||
LABEL_REPEATED = 3;
|
||||
// TODO(sanjay): Should we add LABEL_MAP?
|
||||
};
|
||||
|
||||
optional string name = 1;
|
||||
optional int32 number = 3;
|
||||
optional Label label = 4;
|
||||
|
||||
// If type_name is set, this need not be set. If both this and type_name
|
||||
// are set, this must be either TYPE_ENUM or TYPE_MESSAGE.
|
||||
optional Type type = 5;
|
||||
|
||||
// For message and enum types, this is the name of the type. If the name
|
||||
// starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
|
||||
// rules are used to find the type (i.e. first the nested types within this
|
||||
// message are searched, then within the parent, on up to the root
|
||||
// namespace).
|
||||
optional string type_name = 6;
|
||||
|
||||
// For extensions, this is the name of the type being extended. It is
|
||||
// resolved in the same manner as type_name.
|
||||
optional string extendee = 2;
|
||||
|
||||
// For numeric types, contains the original text representation of the value.
|
||||
// For booleans, "true" or "false".
|
||||
// For strings, contains the default text contents (not escaped in any way).
|
||||
// For bytes, contains the C escaped value. All bytes >= 128 are escaped.
|
||||
// TODO(kenton): Base-64 encode?
|
||||
optional string default_value = 7;
|
||||
|
||||
optional FieldOptions options = 8;
|
||||
}
|
||||
|
||||
// Describes an enum type.
|
||||
message EnumDescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
repeated EnumValueDescriptorProto value = 2;
|
||||
|
||||
optional EnumOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a value within an enum.
|
||||
message EnumValueDescriptorProto {
|
||||
optional string name = 1;
|
||||
optional int32 number = 2;
|
||||
|
||||
optional EnumValueOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a service.
|
||||
message ServiceDescriptorProto {
|
||||
optional string name = 1;
|
||||
repeated MethodDescriptorProto method = 2;
|
||||
|
||||
optional ServiceOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a method of a service.
|
||||
message MethodDescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
// Input and output type names. These are resolved in the same way as
|
||||
// FieldDescriptorProto.type_name, but must refer to a message type.
|
||||
optional string input_type = 2;
|
||||
optional string output_type = 3;
|
||||
|
||||
optional MethodOptions options = 4;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Options
|
||||
|
||||
// Each of the definitions above may have "options" attached. These are
|
||||
// just annotations which may cause code to be generated slightly differently
|
||||
// or may contain hints for code that manipulates protocol messages.
|
||||
//
|
||||
// Clients may define custom options as extensions of the *Options messages.
|
||||
// These extensions may not yet be known at parsing time, so the parser cannot
|
||||
// store the values in them. Instead it stores them in a field in the *Options
|
||||
// message called uninterpreted_option. This field must have the same name
|
||||
// across all *Options messages. We then use this field to populate the
|
||||
// extensions when we build a descriptor, at which point all protos have been
|
||||
// parsed and so all extensions are known.
|
||||
//
|
||||
// Extension numbers for custom options may be chosen as follows:
|
||||
// * For options which will only be used within a single application or
|
||||
// organization, or for experimental options, use field numbers 50000
|
||||
// through 99999. It is up to you to ensure that you do not use the
|
||||
// same number for multiple options.
|
||||
// * For options which will be published and used publicly by multiple
|
||||
// independent entities, e-mail kenton@google.com to reserve extension
|
||||
// numbers. Simply tell me how many you need and I'll send you back a
|
||||
// set of numbers to use -- there's no need to explain how you intend to
|
||||
// use them. If this turns out to be popular, a web service will be set up
|
||||
// to automatically assign option numbers.
|
||||
|
||||
|
||||
message FileOptions {
|
||||
|
||||
// Sets the Java package where classes generated from this .proto will be
|
||||
// placed. By default, the proto package is used, but this is often
|
||||
// inappropriate because proto packages do not normally start with backwards
|
||||
// domain names.
|
||||
optional string java_package = 1;
|
||||
|
||||
|
||||
// If set, all the classes from the .proto file are wrapped in a single
|
||||
// outer class with the given name. This applies to both Proto1
|
||||
// (equivalent to the old "--one_java_file" option) and Proto2 (where
|
||||
// a .proto always translates to a single class, but you may want to
|
||||
// explicitly choose the class name).
|
||||
optional string java_outer_classname = 8;
|
||||
|
||||
// If set true, then the Java code generator will generate a separate .java
|
||||
// file for each top-level message, enum, and service defined in the .proto
|
||||
// file. Thus, these types will *not* be nested inside the outer class
|
||||
// named by java_outer_classname. However, the outer class will still be
|
||||
// generated to contain the file's getDescriptor() method as well as any
|
||||
// top-level extensions defined in the file.
|
||||
optional bool java_multiple_files = 10 [default=false];
|
||||
|
||||
// Generated classes can be optimized for speed or code size.
|
||||
enum OptimizeMode {
|
||||
SPEED = 1; // Generate complete code for parsing, serialization,
|
||||
// etc.
|
||||
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
|
||||
LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
|
||||
}
|
||||
optional OptimizeMode optimize_for = 9 [default=SPEED];
|
||||
|
||||
|
||||
|
||||
|
||||
// Should generic services be generated in each language? "Generic" services
|
||||
// are not specific to any particular RPC system. They are generated by the
|
||||
// main code generators in each language (without additional plugins).
|
||||
// Generic services were the only kind of service generation supported by
|
||||
// early versions of proto2.
|
||||
//
|
||||
// Generic services are now considered deprecated in favor of using plugins
|
||||
// that generate code specific to your particular RPC system. If you are
|
||||
// using such a plugin, set these to false. In the future, we may change
|
||||
// the default to false, so if you explicitly want generic services, you
|
||||
// should explicitly set these to true.
|
||||
optional bool cc_generic_services = 16 [default=true];
|
||||
optional bool java_generic_services = 17 [default=true];
|
||||
optional bool py_generic_services = 18 [default=true];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message MessageOptions {
|
||||
// Set true to use the old proto1 MessageSet wire format for extensions.
|
||||
// This is provided for backwards-compatibility with the MessageSet wire
|
||||
// format. You should not use this for any other reason: It's less
|
||||
// efficient, has fewer features, and is more complicated.
|
||||
//
|
||||
// The message must be defined exactly as follows:
|
||||
// message Foo {
|
||||
// option message_set_wire_format = true;
|
||||
// extensions 4 to max;
|
||||
// }
|
||||
// Note that the message cannot have any defined fields; MessageSets only
|
||||
// have extensions.
|
||||
//
|
||||
// All extensions of your type must be singular messages; e.g. they cannot
|
||||
// be int32s, enums, or repeated messages.
|
||||
//
|
||||
// Because this is an option, the above two restrictions are not enforced by
|
||||
// the protocol compiler.
|
||||
optional bool message_set_wire_format = 1 [default=false];
|
||||
|
||||
// Disables the generation of the standard "descriptor()" accessor, which can
|
||||
// conflict with a field of the same name. This is meant to make migration
|
||||
// from proto1 easier; new code should avoid fields named "descriptor".
|
||||
optional bool no_standard_descriptor_accessor = 2 [default=false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message FieldOptions {
|
||||
// The ctype option instructs the C++ code generator to use a different
|
||||
// representation of the field than it normally would. See the specific
|
||||
// options below. This option is not yet implemented in the open source
|
||||
// release -- sorry, we'll try to include it in a future version!
|
||||
optional CType ctype = 1 [default = STRING];
|
||||
enum CType {
|
||||
// Default mode.
|
||||
STRING = 0;
|
||||
|
||||
CORD = 1;
|
||||
|
||||
STRING_PIECE = 2;
|
||||
}
|
||||
// The packed option can be enabled for repeated primitive fields to enable
|
||||
// a more efficient representation on the wire. Rather than repeatedly
|
||||
// writing the tag and type for each element, the entire array is encoded as
|
||||
// a single length-delimited blob.
|
||||
optional bool packed = 2;
|
||||
|
||||
|
||||
// Is this field deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for accessors, or it will be completely ignored; in the very least, this
|
||||
// is a formalization for deprecating fields.
|
||||
optional bool deprecated = 3 [default=false];
|
||||
|
||||
// EXPERIMENTAL. DO NOT USE.
|
||||
// For "map" fields, the name of the field in the enclosed type that
|
||||
// is the key for this map. For example, suppose we have:
|
||||
// message Item {
|
||||
// required string name = 1;
|
||||
// required string value = 2;
|
||||
// }
|
||||
// message Config {
|
||||
// repeated Item items = 1 [experimental_map_key="name"];
|
||||
// }
|
||||
// In this situation, the map key for Item will be set to "name".
|
||||
// TODO: Fully-implement this, then remove the "experimental_" prefix.
|
||||
optional string experimental_map_key = 9;
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message EnumOptions {
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message EnumValueOptions {
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message ServiceOptions {
|
||||
|
||||
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
||||
// framework. We apologize for hoarding these numbers to ourselves, but
|
||||
// we were already using them long before we decided to release Protocol
|
||||
// Buffers.
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message MethodOptions {
|
||||
|
||||
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
||||
// framework. We apologize for hoarding these numbers to ourselves, but
|
||||
// we were already using them long before we decided to release Protocol
|
||||
// Buffers.
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
// A message representing a option the parser does not recognize. This only
|
||||
// appears in options protos created by the compiler::Parser class.
|
||||
// DescriptorPool resolves these when building Descriptor objects. Therefore,
|
||||
// options protos in descriptor objects (e.g. returned by Descriptor::options(),
|
||||
// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
|
||||
// in them.
|
||||
message UninterpretedOption {
|
||||
// The name of the uninterpreted option. Each string represents a segment in
|
||||
// a dot-separated name. is_extension is true iff a segment represents an
|
||||
// extension (denoted with parentheses in options specs in .proto files).
|
||||
// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
|
||||
// "foo.(bar.baz).qux".
|
||||
message NamePart {
|
||||
required string name_part = 1;
|
||||
required bool is_extension = 2;
|
||||
}
|
||||
repeated NamePart name = 2;
|
||||
|
||||
// The value of the uninterpreted option, in whatever type the tokenizer
|
||||
// identified it as during parsing. Exactly one of these should be set.
|
||||
optional string identifier_value = 3;
|
||||
optional uint64 positive_int_value = 4;
|
||||
optional int64 negative_int_value = 5;
|
||||
optional double double_value = 6;
|
||||
optional bytes string_value = 7;
|
||||
}
|
|
@ -1,541 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/descriptor_database.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/wire_format_lite_inl.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
#include <google/protobuf/stubs/map-util.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
DescriptorDatabase::~DescriptorDatabase() {}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddFile(
|
||||
const FileDescriptorProto& file,
|
||||
Value value) {
|
||||
if (!InsertIfNotPresent(&by_name_, file.name(), value)) {
|
||||
GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must be careful here -- calling file.package() if file.has_package() is
|
||||
// false could access an uninitialized static-storage variable if we are being
|
||||
// run at startup time.
|
||||
string path = file.has_package() ? file.package() : string();
|
||||
if (!path.empty()) path += '.';
|
||||
|
||||
for (int i = 0; i < file.message_type_size(); i++) {
|
||||
if (!AddSymbol(path + file.message_type(i).name(), value)) return false;
|
||||
if (!AddNestedExtensions(file.message_type(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.enum_type_size(); i++) {
|
||||
if (!AddSymbol(path + file.enum_type(i).name(), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.extension_size(); i++) {
|
||||
if (!AddSymbol(path + file.extension(i).name(), value)) return false;
|
||||
if (!AddExtension(file.extension(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.service_size(); i++) {
|
||||
if (!AddSymbol(path + file.service(i).name(), value)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddSymbol(
|
||||
const string& name, Value value) {
|
||||
// We need to make sure not to violate our map invariant.
|
||||
|
||||
// If the symbol name is invalid it could break our lookup algorithm (which
|
||||
// relies on the fact that '.' sorts before all other characters that are
|
||||
// valid in symbol names).
|
||||
if (!ValidateSymbolName(name)) {
|
||||
GOOGLE_LOG(ERROR) << "Invalid symbol name: " << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to look up the symbol to make sure a super-symbol doesn't already
|
||||
// exist.
|
||||
typename map<string, Value>::iterator iter = FindLastLessOrEqual(name);
|
||||
|
||||
if (iter == by_symbol_.end()) {
|
||||
// Apparently the map is currently empty. Just insert and be done with it.
|
||||
by_symbol_.insert(make_pair(name, value));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsSubSymbol(iter->first, name)) {
|
||||
GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing "
|
||||
"symbol \"" << iter->first << "\".";
|
||||
return false;
|
||||
}
|
||||
|
||||
// OK, that worked. Now we have to make sure that no symbol in the map is
|
||||
// a sub-symbol of the one we are inserting. The only symbol which could
|
||||
// be so is the first symbol that is greater than the new symbol. Since
|
||||
// |iter| points at the last symbol that is less than or equal, we just have
|
||||
// to increment it.
|
||||
++iter;
|
||||
|
||||
if (iter != by_symbol_.end() && IsSubSymbol(name, iter->first)) {
|
||||
GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing "
|
||||
"symbol \"" << iter->first << "\".";
|
||||
return false;
|
||||
}
|
||||
|
||||
// OK, no conflicts.
|
||||
|
||||
// Insert the new symbol using the iterator as a hint, the new entry will
|
||||
// appear immediately before the one the iterator is pointing at.
|
||||
by_symbol_.insert(iter, make_pair(name, value));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddNestedExtensions(
|
||||
const DescriptorProto& message_type,
|
||||
Value value) {
|
||||
for (int i = 0; i < message_type.nested_type_size(); i++) {
|
||||
if (!AddNestedExtensions(message_type.nested_type(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < message_type.extension_size(); i++) {
|
||||
if (!AddExtension(message_type.extension(i), value)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddExtension(
|
||||
const FieldDescriptorProto& field,
|
||||
Value value) {
|
||||
if (!field.extendee().empty() && field.extendee()[0] == '.') {
|
||||
// The extension is fully-qualified. We can use it as a lookup key in
|
||||
// the by_symbol_ table.
|
||||
if (!InsertIfNotPresent(&by_extension_,
|
||||
make_pair(field.extendee().substr(1),
|
||||
field.number()),
|
||||
value)) {
|
||||
GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
|
||||
"extend " << field.extendee() << " { "
|
||||
<< field.name() << " = " << field.number() << " }";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Not fully-qualified. We can't really do anything here, unfortunately.
|
||||
// We don't consider this an error, though, because the descriptor is
|
||||
// valid.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindFile(
|
||||
const string& filename) {
|
||||
return FindWithDefault(by_name_, filename, Value());
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindSymbol(
|
||||
const string& name) {
|
||||
typename map<string, Value>::iterator iter = FindLastLessOrEqual(name);
|
||||
|
||||
return (iter != by_symbol_.end() && IsSubSymbol(iter->first, name)) ?
|
||||
iter->second : Value();
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
|
||||
const string& containing_type,
|
||||
int field_number) {
|
||||
return FindWithDefault(by_extension_,
|
||||
make_pair(containing_type, field_number),
|
||||
Value());
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
|
||||
const string& containing_type,
|
||||
vector<int>* output) {
|
||||
typename map<pair<string, int>, Value >::const_iterator it =
|
||||
by_extension_.lower_bound(make_pair(containing_type, 0));
|
||||
bool success = false;
|
||||
|
||||
for (; it != by_extension_.end() && it->first.first == containing_type;
|
||||
++it) {
|
||||
output->push_back(it->first.second);
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
typename map<string, Value>::iterator
|
||||
SimpleDescriptorDatabase::DescriptorIndex<Value>::FindLastLessOrEqual(
|
||||
const string& name) {
|
||||
// Find the last key in the map which sorts less than or equal to the
|
||||
// symbol name. Since upper_bound() returns the *first* key that sorts
|
||||
// *greater* than the input, we want the element immediately before that.
|
||||
typename map<string, Value>::iterator iter = by_symbol_.upper_bound(name);
|
||||
if (iter != by_symbol_.begin()) --iter;
|
||||
return iter;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::IsSubSymbol(
|
||||
const string& sub_symbol, const string& super_symbol) {
|
||||
return sub_symbol == super_symbol ||
|
||||
(HasPrefixString(super_symbol, sub_symbol) &&
|
||||
super_symbol[sub_symbol.size()] == '.');
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::ValidateSymbolName(
|
||||
const string& name) {
|
||||
for (int i = 0; i < name.size(); i++) {
|
||||
// I don't trust ctype.h due to locales. :(
|
||||
if (name[i] != '.' && name[i] != '_' &&
|
||||
(name[i] < '0' || name[i] > '9') &&
|
||||
(name[i] < 'A' || name[i] > 'Z') &&
|
||||
(name[i] < 'a' || name[i] > 'z')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
|
||||
SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {
|
||||
STLDeleteElements(&files_to_delete_);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
|
||||
FileDescriptorProto* new_file = new FileDescriptorProto;
|
||||
new_file->CopyFrom(file);
|
||||
return AddAndOwn(new_file);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
|
||||
files_to_delete_.push_back(file);
|
||||
return index_.AddFile(*file, file);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindFile(filename), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindSymbol(symbol_name), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindExtension(containing_type, field_number), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
return index_.FindAllExtensionNumbers(extendee_type, output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file,
|
||||
FileDescriptorProto* output) {
|
||||
if (file == NULL) return false;
|
||||
output->CopyFrom(*file);
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
EncodedDescriptorDatabase::EncodedDescriptorDatabase() {}
|
||||
EncodedDescriptorDatabase::~EncodedDescriptorDatabase() {
|
||||
for (int i = 0; i < files_to_delete_.size(); i++) {
|
||||
operator delete(files_to_delete_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::Add(
|
||||
const void* encoded_file_descriptor, int size) {
|
||||
FileDescriptorProto file;
|
||||
if (file.ParseFromArray(encoded_file_descriptor, size)) {
|
||||
return index_.AddFile(file, make_pair(encoded_file_descriptor, size));
|
||||
} else {
|
||||
GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
|
||||
"EncodedDescriptorDatabase::Add().";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::AddCopy(
|
||||
const void* encoded_file_descriptor, int size) {
|
||||
void* copy = operator new(size);
|
||||
memcpy(copy, encoded_file_descriptor, size);
|
||||
files_to_delete_.push_back(copy);
|
||||
return Add(copy, size);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindFile(filename), output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindSymbol(symbol_name), output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
string* output) {
|
||||
pair<const void*, int> encoded_file = index_.FindSymbol(symbol_name);
|
||||
if (encoded_file.first == NULL) return false;
|
||||
|
||||
// Optimization: The name should be the first field in the encoded message.
|
||||
// Try to just read it directly.
|
||||
io::CodedInputStream input(reinterpret_cast<const uint8*>(encoded_file.first),
|
||||
encoded_file.second);
|
||||
|
||||
const uint32 kNameTag = internal::WireFormatLite::MakeTag(
|
||||
FileDescriptorProto::kNameFieldNumber,
|
||||
internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
if (input.ReadTag() == kNameTag) {
|
||||
// Success!
|
||||
return internal::WireFormatLite::ReadString(&input, output);
|
||||
} else {
|
||||
// Slow path. Parse whole message.
|
||||
FileDescriptorProto file_proto;
|
||||
if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) {
|
||||
return false;
|
||||
}
|
||||
*output = file_proto.name();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindExtension(containing_type, field_number),
|
||||
output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
return index_.FindAllExtensionNumbers(extendee_type, output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::MaybeParse(
|
||||
pair<const void*, int> encoded_file,
|
||||
FileDescriptorProto* output) {
|
||||
if (encoded_file.first == NULL) return false;
|
||||
return output->ParseFromArray(encoded_file.first, encoded_file.second);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
|
||||
: pool_(pool) {}
|
||||
DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
const FileDescriptor* file = pool_.FindFileByName(filename);
|
||||
if (file == NULL) return false;
|
||||
output->Clear();
|
||||
file->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name);
|
||||
if (file == NULL) return false;
|
||||
output->Clear();
|
||||
file->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type);
|
||||
if (extendee == NULL) return false;
|
||||
|
||||
const FieldDescriptor* extension =
|
||||
pool_.FindExtensionByNumber(extendee, field_number);
|
||||
if (extension == NULL) return false;
|
||||
|
||||
output->Clear();
|
||||
extension->file()->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
const Descriptor* extendee = pool_.FindMessageTypeByName(extendee_type);
|
||||
if (extendee == NULL) return false;
|
||||
|
||||
vector<const FieldDescriptor*> extensions;
|
||||
pool_.FindAllExtensions(extendee, &extensions);
|
||||
|
||||
for (int i = 0; i < extensions.size(); ++i) {
|
||||
output->push_back(extensions[i]->number());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MergedDescriptorDatabase::MergedDescriptorDatabase(
|
||||
DescriptorDatabase* source1,
|
||||
DescriptorDatabase* source2) {
|
||||
sources_.push_back(source1);
|
||||
sources_.push_back(source2);
|
||||
}
|
||||
MergedDescriptorDatabase::MergedDescriptorDatabase(
|
||||
const vector<DescriptorDatabase*>& sources)
|
||||
: sources_(sources) {}
|
||||
MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileByName(filename, output)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileContainingSymbol(symbol_name, output)) {
|
||||
// The symbol was found in source i. However, if one of the previous
|
||||
// sources defines a file with the same name (which presumably doesn't
|
||||
// contain the symbol, since it wasn't found in that source), then we
|
||||
// must hide it from the caller.
|
||||
FileDescriptorProto temp;
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (sources_[j]->FindFileByName(output->name(), &temp)) {
|
||||
// Found conflicting file in a previous source.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileContainingExtension(
|
||||
containing_type, field_number, output)) {
|
||||
// The symbol was found in source i. However, if one of the previous
|
||||
// sources defines a file with the same name (which presumably doesn't
|
||||
// contain the symbol, since it wasn't found in that source), then we
|
||||
// must hide it from the caller.
|
||||
FileDescriptorProto temp;
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (sources_[j]->FindFileByName(output->name(), &temp)) {
|
||||
// Found conflicting file in a previous source.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
set<int> merged_results;
|
||||
vector<int> results;
|
||||
bool success = false;
|
||||
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
|
||||
copy(results.begin(), results.end(),
|
||||
insert_iterator<set<int> >(merged_results, merged_results.begin()));
|
||||
success = true;
|
||||
}
|
||||
results.clear();
|
||||
}
|
||||
|
||||
copy(merged_results.begin(), merged_results.end(),
|
||||
insert_iterator<vector<int> >(*output, output->end()));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,366 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Interface for manipulating databases of descriptors.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in this file.
|
||||
class DescriptorDatabase;
|
||||
class SimpleDescriptorDatabase;
|
||||
class EncodedDescriptorDatabase;
|
||||
class DescriptorPoolDatabase;
|
||||
class MergedDescriptorDatabase;
|
||||
|
||||
// Abstract interface for a database of descriptors.
|
||||
//
|
||||
// This is useful if you want to create a DescriptorPool which loads
|
||||
// descriptors on-demand from some sort of large database. If the database
|
||||
// is large, it may be inefficient to enumerate every .proto file inside it
|
||||
// calling DescriptorPool::BuildFile() for each one. Instead, a DescriptorPool
|
||||
// can be created which wraps a DescriptorDatabase and only builds particular
|
||||
// descriptors when they are needed.
|
||||
class LIBPROTOBUF_EXPORT DescriptorDatabase {
|
||||
public:
|
||||
inline DescriptorDatabase() {}
|
||||
virtual ~DescriptorDatabase();
|
||||
|
||||
// Find a file by file name. Fills in in *output and returns true if found.
|
||||
// Otherwise, returns false, leaving the contents of *output undefined.
|
||||
virtual bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Find the file that declares the given fully-qualified symbol name.
|
||||
// If found, fills in *output and returns true, otherwise returns false
|
||||
// and leaves *output undefined.
|
||||
virtual bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Find the file which defines an extension extending the given message type
|
||||
// with the given field number. If found, fills in *output and returns true,
|
||||
// otherwise returns false and leaves *output undefined. containing_type
|
||||
// must be a fully-qualified type name.
|
||||
virtual bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Finds the tag numbers used by all known extensions of
|
||||
// extendee_type, and appends them to output in an undefined
|
||||
// order. This method is best-effort: it's not guaranteed that the
|
||||
// database will find all extensions, and it's not guaranteed that
|
||||
// FindFileContainingExtension will return true on all of the found
|
||||
// numbers. Returns true if the search was successful, otherwise
|
||||
// returns false and leaves output unchanged.
|
||||
//
|
||||
// This method has a default implementation that always returns
|
||||
// false.
|
||||
virtual bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase into which you can insert files manually.
|
||||
//
|
||||
// FindFileContainingSymbol() is fully-implemented. When you add a file, its
|
||||
// symbols will be indexed for this purpose. Note that the implementation
|
||||
// may return false positives, but only if it isn't possible for the symbol
|
||||
// to be defined in any other file. In particular, if a file defines a symbol
|
||||
// "Foo", then searching for "Foo.[anything]" will match that file. This way,
|
||||
// the database does not need to aggressively index all children of a symbol.
|
||||
//
|
||||
// FindFileContainingExtension() is mostly-implemented. It works if and only
|
||||
// if the original FieldDescriptorProto defining the extension has a
|
||||
// fully-qualified type name in its "extendee" field (i.e. starts with a '.').
|
||||
// If the extendee is a relative name, SimpleDescriptorDatabase will not
|
||||
// attempt to resolve the type, so it will not know what type the extension is
|
||||
// extending. Therefore, calling FindFileContainingExtension() with the
|
||||
// extension's containing type will never actually find that extension. Note
|
||||
// that this is an unlikely problem, as all FileDescriptorProtos created by the
|
||||
// protocol compiler (as well as ones created by calling
|
||||
// FileDescriptor::CopyTo()) will always use fully-qualified names for all
|
||||
// types. You only need to worry if you are constructing FileDescriptorProtos
|
||||
// yourself, or are calling compiler::Parser directly.
|
||||
class LIBPROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
SimpleDescriptorDatabase();
|
||||
~SimpleDescriptorDatabase();
|
||||
|
||||
// Adds the FileDescriptorProto to the database, making a copy. The object
|
||||
// can be deleted after Add() returns. Returns false if the file conflicted
|
||||
// with a file already in the database, in which case an error will have
|
||||
// been written to GOOGLE_LOG(ERROR).
|
||||
bool Add(const FileDescriptorProto& file);
|
||||
|
||||
// Adds the FileDescriptorProto to the database and takes ownership of it.
|
||||
bool AddAndOwn(const FileDescriptorProto* file);
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
// So that it can use DescriptorIndex.
|
||||
friend class EncodedDescriptorDatabase;
|
||||
|
||||
// An index mapping file names, symbol names, and extension numbers to
|
||||
// some sort of values.
|
||||
template <typename Value>
|
||||
class DescriptorIndex {
|
||||
public:
|
||||
// Helpers to recursively add particular descriptors and all their contents
|
||||
// to the index.
|
||||
bool AddFile(const FileDescriptorProto& file,
|
||||
Value value);
|
||||
bool AddSymbol(const string& name, Value value);
|
||||
bool AddNestedExtensions(const DescriptorProto& message_type,
|
||||
Value value);
|
||||
bool AddExtension(const FieldDescriptorProto& field,
|
||||
Value value);
|
||||
|
||||
Value FindFile(const string& filename);
|
||||
Value FindSymbol(const string& name);
|
||||
Value FindExtension(const string& containing_type, int field_number);
|
||||
bool FindAllExtensionNumbers(const string& containing_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
map<string, Value> by_name_;
|
||||
map<string, Value> by_symbol_;
|
||||
map<pair<string, int>, Value> by_extension_;
|
||||
|
||||
// Invariant: The by_symbol_ map does not contain any symbols which are
|
||||
// prefixes of other symbols in the map. For example, "foo.bar" is a
|
||||
// prefix of "foo.bar.baz" (but is not a prefix of "foo.barbaz").
|
||||
//
|
||||
// This invariant is important because it means that given a symbol name,
|
||||
// we can find a key in the map which is a prefix of the symbol in O(lg n)
|
||||
// time, and we know that there is at most one such key.
|
||||
//
|
||||
// The prefix lookup algorithm works like so:
|
||||
// 1) Find the last key in the map which is less than or equal to the
|
||||
// search key.
|
||||
// 2) If the found key is a prefix of the search key, then return it.
|
||||
// Otherwise, there is no match.
|
||||
//
|
||||
// I am sure this algorithm has been described elsewhere, but since I
|
||||
// wasn't able to find it quickly I will instead prove that it works
|
||||
// myself. The key to the algorithm is that if a match exists, step (1)
|
||||
// will find it. Proof:
|
||||
// 1) Define the "search key" to be the key we are looking for, the "found
|
||||
// key" to be the key found in step (1), and the "match key" to be the
|
||||
// key which actually matches the serach key (i.e. the key we're trying
|
||||
// to find).
|
||||
// 2) The found key must be less than or equal to the search key by
|
||||
// definition.
|
||||
// 3) The match key must also be less than or equal to the search key
|
||||
// (because it is a prefix).
|
||||
// 4) The match key cannot be greater than the found key, because if it
|
||||
// were, then step (1) of the algorithm would have returned the match
|
||||
// key instead (since it finds the *greatest* key which is less than or
|
||||
// equal to the search key).
|
||||
// 5) Therefore, the found key must be between the match key and the search
|
||||
// key, inclusive.
|
||||
// 6) Since the search key must be a sub-symbol of the match key, if it is
|
||||
// not equal to the match key, then search_key[match_key.size()] must
|
||||
// be '.'.
|
||||
// 7) Since '.' sorts before any other character that is valid in a symbol
|
||||
// name, then if the found key is not equal to the match key, then
|
||||
// found_key[match_key.size()] must also be '.', because any other value
|
||||
// would make it sort after the search key.
|
||||
// 8) Therefore, if the found key is not equal to the match key, then the
|
||||
// found key must be a sub-symbol of the match key. However, this would
|
||||
// contradict our map invariant which says that no symbol in the map is
|
||||
// a sub-symbol of any other.
|
||||
// 9) Therefore, the found key must match the match key.
|
||||
//
|
||||
// The above proof assumes the match key exists. In the case that the
|
||||
// match key does not exist, then step (1) will return some other symbol.
|
||||
// That symbol cannot be a super-symbol of the search key since if it were,
|
||||
// then it would be a match, and we're assuming the match key doesn't exist.
|
||||
// Therefore, step 2 will correctly return no match.
|
||||
|
||||
// Find the last entry in the by_symbol_ map whose key is less than or
|
||||
// equal to the given name.
|
||||
typename map<string, Value>::iterator FindLastLessOrEqual(
|
||||
const string& name);
|
||||
|
||||
// True if either the arguments are equal or super_symbol identifies a
|
||||
// parent symbol of sub_symbol (e.g. "foo.bar" is a parent of
|
||||
// "foo.bar.baz", but not a parent of "foo.barbaz").
|
||||
bool IsSubSymbol(const string& sub_symbol, const string& super_symbol);
|
||||
|
||||
// Returns true if and only if all characters in the name are alphanumerics,
|
||||
// underscores, or periods.
|
||||
bool ValidateSymbolName(const string& name);
|
||||
};
|
||||
|
||||
|
||||
DescriptorIndex<const FileDescriptorProto*> index_;
|
||||
vector<const FileDescriptorProto*> files_to_delete_;
|
||||
|
||||
// If file is non-NULL, copy it into *output and return true, otherwise
|
||||
// return false.
|
||||
bool MaybeCopy(const FileDescriptorProto* file,
|
||||
FileDescriptorProto* output);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleDescriptorDatabase);
|
||||
};
|
||||
|
||||
// Very similar to SimpleDescriptorDatabase, but stores all the descriptors
|
||||
// as raw bytes and generally tries to use as little memory as possible.
|
||||
//
|
||||
// The same caveats regarding FindFileContainingExtension() apply as with
|
||||
// SimpleDescriptorDatabase.
|
||||
class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
EncodedDescriptorDatabase();
|
||||
~EncodedDescriptorDatabase();
|
||||
|
||||
// Adds the FileDescriptorProto to the database. The descriptor is provided
|
||||
// in encoded form. The database does not make a copy of the bytes, nor
|
||||
// does it take ownership; it's up to the caller to make sure the bytes
|
||||
// remain valid for the life of the database. Returns false and logs an error
|
||||
// if the bytes are not a valid FileDescriptorProto or if the file conflicted
|
||||
// with a file already in the database.
|
||||
bool Add(const void* encoded_file_descriptor, int size);
|
||||
|
||||
// Like Add(), but makes a copy of the data, so that the caller does not
|
||||
// need to keep it around.
|
||||
bool AddCopy(const void* encoded_file_descriptor, int size);
|
||||
|
||||
// Like FindFileContainingSymbol but returns only the name of the file.
|
||||
bool FindNameOfFileContainingSymbol(const string& symbol_name,
|
||||
string* output);
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
SimpleDescriptorDatabase::DescriptorIndex<pair<const void*, int> > index_;
|
||||
vector<void*> files_to_delete_;
|
||||
|
||||
// If encoded_file.first is non-NULL, parse the data into *output and return
|
||||
// true, otherwise return false.
|
||||
bool MaybeParse(pair<const void*, int> encoded_file,
|
||||
FileDescriptorProto* output);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EncodedDescriptorDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase that fetches files from a given pool.
|
||||
class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
DescriptorPoolDatabase(const DescriptorPool& pool);
|
||||
~DescriptorPoolDatabase();
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
const DescriptorPool& pool_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPoolDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase that wraps two or more others. It first searches the
|
||||
// first database and, if that fails, tries the second, and so on.
|
||||
class LIBPROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
// Merge just two databases. The sources remain property of the caller.
|
||||
MergedDescriptorDatabase(DescriptorDatabase* source1,
|
||||
DescriptorDatabase* source2);
|
||||
// Merge more than two databases. The sources remain property of the caller.
|
||||
// The vector may be deleted after the constructor returns but the
|
||||
// DescriptorDatabases need to stick around.
|
||||
MergedDescriptorDatabase(const vector<DescriptorDatabase*>& sources);
|
||||
~MergedDescriptorDatabase();
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
// Merges the results of calling all databases. Returns true iff any
|
||||
// of the databases returned true.
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
vector<DescriptorDatabase*> sources_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MergedDescriptorDatabase);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
|
@ -1,748 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file makes extensive use of RFC 3092. :)
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <google/protobuf/descriptor_database.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/text_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
|
||||
static void AddToDatabase(SimpleDescriptorDatabase* database,
|
||||
const char* file_text) {
|
||||
FileDescriptorProto file_proto;
|
||||
EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
|
||||
database->Add(file_proto);
|
||||
}
|
||||
|
||||
static void ExpectContainsType(const FileDescriptorProto& proto,
|
||||
const string& type_name) {
|
||||
for (int i = 0; i < proto.message_type_size(); i++) {
|
||||
if (proto.message_type(i).name() == type_name) return;
|
||||
}
|
||||
ADD_FAILURE() << "\"" << proto.name()
|
||||
<< "\" did not contain expected type \""
|
||||
<< type_name << "\".";
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
// SimpleDescriptorDatabase, EncodedDescriptorDatabase, and
|
||||
// DescriptorPoolDatabase call for very similar tests. Instead of writing
|
||||
// three nearly-identical sets of tests, we use parameterized tests to apply
|
||||
// the same code to all three.
|
||||
|
||||
// The parameterized test runs against a DescriptarDatabaseTestCase. We have
|
||||
// implementations for each of the three classes we want to test.
|
||||
class DescriptorDatabaseTestCase {
|
||||
public:
|
||||
virtual ~DescriptorDatabaseTestCase() {}
|
||||
|
||||
virtual DescriptorDatabase* GetDatabase() = 0;
|
||||
virtual bool AddToDatabase(const FileDescriptorProto& file) = 0;
|
||||
};
|
||||
|
||||
// Factory function type.
|
||||
typedef DescriptorDatabaseTestCase* DescriptorDatabaseTestCaseFactory();
|
||||
|
||||
// Specialization for SimpleDescriptorDatabase.
|
||||
class SimpleDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase {
|
||||
public:
|
||||
static DescriptorDatabaseTestCase* New() {
|
||||
return new SimpleDescriptorDatabaseTestCase;
|
||||
}
|
||||
|
||||
virtual ~SimpleDescriptorDatabaseTestCase() {}
|
||||
|
||||
virtual DescriptorDatabase* GetDatabase() {
|
||||
return &database_;
|
||||
}
|
||||
virtual bool AddToDatabase(const FileDescriptorProto& file) {
|
||||
return database_.Add(file);
|
||||
}
|
||||
|
||||
private:
|
||||
SimpleDescriptorDatabase database_;
|
||||
};
|
||||
|
||||
// Specialization for EncodedDescriptorDatabase.
|
||||
class EncodedDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase {
|
||||
public:
|
||||
static DescriptorDatabaseTestCase* New() {
|
||||
return new EncodedDescriptorDatabaseTestCase;
|
||||
}
|
||||
|
||||
virtual ~EncodedDescriptorDatabaseTestCase() {}
|
||||
|
||||
virtual DescriptorDatabase* GetDatabase() {
|
||||
return &database_;
|
||||
}
|
||||
virtual bool AddToDatabase(const FileDescriptorProto& file) {
|
||||
string data;
|
||||
file.SerializeToString(&data);
|
||||
return database_.AddCopy(data.data(), data.size());
|
||||
}
|
||||
|
||||
private:
|
||||
EncodedDescriptorDatabase database_;
|
||||
};
|
||||
|
||||
// Specialization for DescriptorPoolDatabase.
|
||||
class DescriptorPoolDatabaseTestCase : public DescriptorDatabaseTestCase {
|
||||
public:
|
||||
static DescriptorDatabaseTestCase* New() {
|
||||
return new EncodedDescriptorDatabaseTestCase;
|
||||
}
|
||||
|
||||
DescriptorPoolDatabaseTestCase() : database_(pool_) {}
|
||||
virtual ~DescriptorPoolDatabaseTestCase() {}
|
||||
|
||||
virtual DescriptorDatabase* GetDatabase() {
|
||||
return &database_;
|
||||
}
|
||||
virtual bool AddToDatabase(const FileDescriptorProto& file) {
|
||||
return pool_.BuildFile(file);
|
||||
}
|
||||
|
||||
private:
|
||||
DescriptorPool pool_;
|
||||
DescriptorPoolDatabase database_;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
class DescriptorDatabaseTest
|
||||
: public testing::TestWithParam<DescriptorDatabaseTestCaseFactory*> {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
test_case_.reset(GetParam()());
|
||||
database_ = test_case_->GetDatabase();
|
||||
}
|
||||
|
||||
void AddToDatabase(const char* file_descriptor_text) {
|
||||
FileDescriptorProto file_proto;
|
||||
EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto));
|
||||
EXPECT_TRUE(test_case_->AddToDatabase(file_proto));
|
||||
}
|
||||
|
||||
void AddToDatabaseWithError(const char* file_descriptor_text) {
|
||||
FileDescriptorProto file_proto;
|
||||
EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto));
|
||||
EXPECT_FALSE(test_case_->AddToDatabase(file_proto));
|
||||
}
|
||||
|
||||
scoped_ptr<DescriptorDatabaseTestCase> test_case_;
|
||||
DescriptorDatabase* database_;
|
||||
};
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, FindFileByName) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { name:\"Foo\" }");
|
||||
AddToDatabase(
|
||||
"name: \"bar.proto\" "
|
||||
"message_type { name:\"Bar\" }");
|
||||
|
||||
{
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileByName("foo.proto", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
ExpectContainsType(file, "Foo");
|
||||
}
|
||||
|
||||
{
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileByName("bar.proto", &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
ExpectContainsType(file, "Bar");
|
||||
}
|
||||
|
||||
{
|
||||
// Fails to find undefined files.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileByName("baz.proto", &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, FindFileContainingSymbol) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
" field { name:\"qux\" }"
|
||||
" nested_type { name: \"Grault\" } "
|
||||
" enum_type { name: \"Garply\" } "
|
||||
"} "
|
||||
"enum_type { "
|
||||
" name: \"Waldo\" "
|
||||
" value { name:\"FRED\" } "
|
||||
"} "
|
||||
"extension { name: \"plugh\" } "
|
||||
"service { "
|
||||
" name: \"Xyzzy\" "
|
||||
" method { name: \"Thud\" } "
|
||||
"}"
|
||||
);
|
||||
AddToDatabase(
|
||||
"name: \"bar.proto\" "
|
||||
"package: \"corge\" "
|
||||
"message_type { name: \"Bar\" }");
|
||||
|
||||
{
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Foo", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find fields.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.qux", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find nested types.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Grault", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find nested enums.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Garply", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find enum types.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find enum values.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo.FRED", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find extensions.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("plugh", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find services.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find methods.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy.Thud", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find things in packages.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("corge.Bar", &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Fails to find undefined symbols.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileContainingSymbol("Baz", &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Names must be fully-qualified.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileContainingSymbol("Bar", &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, FindFileContainingExtension) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
" extension_range { start: 1 end: 1000 } "
|
||||
" extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
|
||||
" extendee: \".Foo\" }"
|
||||
"}");
|
||||
AddToDatabase(
|
||||
"name: \"bar.proto\" "
|
||||
"package: \"corge\" "
|
||||
"dependency: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Bar\" "
|
||||
" extension_range { start: 1 end: 1000 } "
|
||||
"} "
|
||||
"extension { name:\"grault\" extendee: \".Foo\" number:32 } "
|
||||
"extension { name:\"garply\" extendee: \".corge.Bar\" number:70 } "
|
||||
"extension { name:\"waldo\" extendee: \"Bar\" number:56 } ");
|
||||
|
||||
{
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 5, &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 32, &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find extensions for qualified type names.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingExtension("corge.Bar", 70, &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions whose extendee was not fully-qualified in the
|
||||
// FileDescriptorProto.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 56, &file));
|
||||
EXPECT_FALSE(
|
||||
database_->FindFileContainingExtension("corge.Bar", 56, &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find non-existent extension numbers.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileContainingExtension("Foo", 12, &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions for non-existent types.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(
|
||||
database_->FindFileContainingExtension("NoSuchType", 5, &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions for unqualified type names.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 70, &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, FindAllExtensionNumbers) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
" extension_range { start: 1 end: 1000 } "
|
||||
" extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
|
||||
" extendee: \".Foo\" }"
|
||||
"}");
|
||||
AddToDatabase(
|
||||
"name: \"bar.proto\" "
|
||||
"package: \"corge\" "
|
||||
"dependency: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Bar\" "
|
||||
" extension_range { start: 1 end: 1000 } "
|
||||
"} "
|
||||
"extension { name:\"grault\" extendee: \".Foo\" number:32 } "
|
||||
"extension { name:\"garply\" extendee: \".corge.Bar\" number:70 } "
|
||||
"extension { name:\"waldo\" extendee: \"Bar\" number:56 } ");
|
||||
|
||||
{
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(database_->FindAllExtensionNumbers("Foo", &numbers));
|
||||
ASSERT_EQ(2, numbers.size());
|
||||
sort(numbers.begin(), numbers.end());
|
||||
EXPECT_EQ(5, numbers[0]);
|
||||
EXPECT_EQ(32, numbers[1]);
|
||||
}
|
||||
|
||||
{
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(database_->FindAllExtensionNumbers("corge.Bar", &numbers));
|
||||
// Note: won't find extension 56 due to the name not being fully qualified.
|
||||
ASSERT_EQ(1, numbers.size());
|
||||
EXPECT_EQ(70, numbers[0]);
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions for non-existent types.
|
||||
vector<int> numbers;
|
||||
EXPECT_FALSE(database_->FindAllExtensionNumbers("NoSuchType", &numbers));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions for unqualified types.
|
||||
vector<int> numbers;
|
||||
EXPECT_FALSE(database_->FindAllExtensionNumbers("Bar", &numbers));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, ConflictingFileError) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
"}");
|
||||
AddToDatabaseWithError(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Bar\" "
|
||||
"}");
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, ConflictingTypeError) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
"}");
|
||||
AddToDatabaseWithError(
|
||||
"name: \"bar.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
"}");
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, ConflictingExtensionError) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
|
||||
" extendee: \".Foo\" }");
|
||||
AddToDatabaseWithError(
|
||||
"name: \"bar.proto\" "
|
||||
"extension { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
|
||||
" extendee: \".Foo\" }");
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Simple, DescriptorDatabaseTest,
|
||||
testing::Values(&SimpleDescriptorDatabaseTestCase::New));
|
||||
INSTANTIATE_TEST_CASE_P(MemoryConserving, DescriptorDatabaseTest,
|
||||
testing::Values(&EncodedDescriptorDatabaseTestCase::New));
|
||||
INSTANTIATE_TEST_CASE_P(Pool, DescriptorDatabaseTest,
|
||||
testing::Values(&DescriptorPoolDatabaseTestCase::New));
|
||||
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
TEST(EncodedDescriptorDatabaseExtraTest, FindNameOfFileContainingSymbol) {
|
||||
// Create two files, one of which is in two parts.
|
||||
FileDescriptorProto file1, file2a, file2b;
|
||||
file1.set_name("foo.proto");
|
||||
file1.set_package("foo");
|
||||
file1.add_message_type()->set_name("Foo");
|
||||
file2a.set_name("bar.proto");
|
||||
file2b.set_package("bar");
|
||||
file2b.add_message_type()->set_name("Bar");
|
||||
|
||||
// Normal serialization allows our optimization to kick in.
|
||||
string data1 = file1.SerializeAsString();
|
||||
|
||||
// Force out-of-order serialization to test slow path.
|
||||
string data2 = file2b.SerializeAsString() + file2a.SerializeAsString();
|
||||
|
||||
// Create EncodedDescriptorDatabase containing both files.
|
||||
EncodedDescriptorDatabase db;
|
||||
db.Add(data1.data(), data1.size());
|
||||
db.Add(data2.data(), data2.size());
|
||||
|
||||
// Test!
|
||||
string filename;
|
||||
EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo", &filename));
|
||||
EXPECT_EQ("foo.proto", filename);
|
||||
EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo.Blah", &filename));
|
||||
EXPECT_EQ("foo.proto", filename);
|
||||
EXPECT_TRUE(db.FindNameOfFileContainingSymbol("bar.Bar", &filename));
|
||||
EXPECT_EQ("bar.proto", filename);
|
||||
EXPECT_FALSE(db.FindNameOfFileContainingSymbol("foo", &filename));
|
||||
EXPECT_FALSE(db.FindNameOfFileContainingSymbol("bar", &filename));
|
||||
EXPECT_FALSE(db.FindNameOfFileContainingSymbol("baz.Baz", &filename));
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
class MergedDescriptorDatabaseTest : public testing::Test {
|
||||
protected:
|
||||
MergedDescriptorDatabaseTest()
|
||||
: forward_merged_(&database1_, &database2_),
|
||||
reverse_merged_(&database2_, &database1_) {}
|
||||
|
||||
virtual void SetUp() {
|
||||
AddToDatabase(&database1_,
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { name:\"Foo\" extension_range { start: 1 end: 100 } } "
|
||||
"extension { name:\"foo_ext\" extendee: \".Foo\" number:3 "
|
||||
" label:LABEL_OPTIONAL type:TYPE_INT32 } ");
|
||||
AddToDatabase(&database2_,
|
||||
"name: \"bar.proto\" "
|
||||
"message_type { name:\"Bar\" extension_range { start: 1 end: 100 } } "
|
||||
"extension { name:\"bar_ext\" extendee: \".Bar\" number:5 "
|
||||
" label:LABEL_OPTIONAL type:TYPE_INT32 } ");
|
||||
|
||||
// baz.proto exists in both pools, with different definitions.
|
||||
AddToDatabase(&database1_,
|
||||
"name: \"baz.proto\" "
|
||||
"message_type { name:\"Baz\" extension_range { start: 1 end: 100 } } "
|
||||
"message_type { name:\"FromPool1\" } "
|
||||
"extension { name:\"baz_ext\" extendee: \".Baz\" number:12 "
|
||||
" label:LABEL_OPTIONAL type:TYPE_INT32 } "
|
||||
"extension { name:\"database1_only_ext\" extendee: \".Baz\" number:13 "
|
||||
" label:LABEL_OPTIONAL type:TYPE_INT32 } ");
|
||||
AddToDatabase(&database2_,
|
||||
"name: \"baz.proto\" "
|
||||
"message_type { name:\"Baz\" extension_range { start: 1 end: 100 } } "
|
||||
"message_type { name:\"FromPool2\" } "
|
||||
"extension { name:\"baz_ext\" extendee: \".Baz\" number:12 "
|
||||
" label:LABEL_OPTIONAL type:TYPE_INT32 } ");
|
||||
}
|
||||
|
||||
SimpleDescriptorDatabase database1_;
|
||||
SimpleDescriptorDatabase database2_;
|
||||
|
||||
MergedDescriptorDatabase forward_merged_;
|
||||
MergedDescriptorDatabase reverse_merged_;
|
||||
};
|
||||
|
||||
TEST_F(MergedDescriptorDatabaseTest, FindFileByName) {
|
||||
{
|
||||
// Can find file that is only in database1_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileByName("foo.proto", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
ExpectContainsType(file, "Foo");
|
||||
}
|
||||
|
||||
{
|
||||
// Can find file that is only in database2_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileByName("bar.proto", &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
ExpectContainsType(file, "Bar");
|
||||
}
|
||||
|
||||
{
|
||||
// In forward_merged_, database1_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileByName("baz.proto", &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool1");
|
||||
}
|
||||
|
||||
{
|
||||
// In reverse_merged_, database2_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(reverse_merged_.FindFileByName("baz.proto", &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool2");
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find non-existent file.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(forward_merged_.FindFileByName("no_such.proto", &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MergedDescriptorDatabaseTest, FindFileContainingSymbol) {
|
||||
{
|
||||
// Can find file that is only in database1_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Foo", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
ExpectContainsType(file, "Foo");
|
||||
}
|
||||
|
||||
{
|
||||
// Can find file that is only in database2_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Bar", &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
ExpectContainsType(file, "Bar");
|
||||
}
|
||||
|
||||
{
|
||||
// In forward_merged_, database1_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Baz", &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool1");
|
||||
}
|
||||
|
||||
{
|
||||
// In reverse_merged_, database2_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(reverse_merged_.FindFileContainingSymbol("Baz", &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool2");
|
||||
}
|
||||
|
||||
{
|
||||
// FromPool1 only shows up in forward_merged_ because it is masked by
|
||||
// database2_'s baz.proto in reverse_merged_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("FromPool1", &file));
|
||||
EXPECT_FALSE(reverse_merged_.FindFileContainingSymbol("FromPool1", &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find non-existent symbol.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(
|
||||
forward_merged_.FindFileContainingSymbol("NoSuchType", &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MergedDescriptorDatabaseTest, FindFileContainingExtension) {
|
||||
{
|
||||
// Can find file that is only in database1_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(
|
||||
forward_merged_.FindFileContainingExtension("Foo", 3, &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
ExpectContainsType(file, "Foo");
|
||||
}
|
||||
|
||||
{
|
||||
// Can find file that is only in database2_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(
|
||||
forward_merged_.FindFileContainingExtension("Bar", 5, &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
ExpectContainsType(file, "Bar");
|
||||
}
|
||||
|
||||
{
|
||||
// In forward_merged_, database1_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(
|
||||
forward_merged_.FindFileContainingExtension("Baz", 12, &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool1");
|
||||
}
|
||||
|
||||
{
|
||||
// In reverse_merged_, database2_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(
|
||||
reverse_merged_.FindFileContainingExtension("Baz", 12, &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool2");
|
||||
}
|
||||
|
||||
{
|
||||
// Baz's extension 13 only shows up in forward_merged_ because it is
|
||||
// masked by database2_'s baz.proto in reverse_merged_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileContainingExtension("Baz", 13, &file));
|
||||
EXPECT_FALSE(reverse_merged_.FindFileContainingExtension("Baz", 13, &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find non-existent extension.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(
|
||||
forward_merged_.FindFileContainingExtension("Foo", 6, &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MergedDescriptorDatabaseTest, FindAllExtensionNumbers) {
|
||||
{
|
||||
// Message only has extension in database1_
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Foo", &numbers));
|
||||
ASSERT_EQ(1, numbers.size());
|
||||
EXPECT_EQ(3, numbers[0]);
|
||||
}
|
||||
|
||||
{
|
||||
// Message only has extension in database2_
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Bar", &numbers));
|
||||
ASSERT_EQ(1, numbers.size());
|
||||
EXPECT_EQ(5, numbers[0]);
|
||||
}
|
||||
|
||||
{
|
||||
// Merge results from the two databases.
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Baz", &numbers));
|
||||
ASSERT_EQ(2, numbers.size());
|
||||
sort(numbers.begin(), numbers.end());
|
||||
EXPECT_EQ(12, numbers[0]);
|
||||
EXPECT_EQ(13, numbers[1]);
|
||||
}
|
||||
|
||||
{
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(reverse_merged_.FindAllExtensionNumbers("Baz", &numbers));
|
||||
ASSERT_EQ(2, numbers.size());
|
||||
sort(numbers.begin(), numbers.end());
|
||||
EXPECT_EQ(12, numbers[0]);
|
||||
EXPECT_EQ(13, numbers[1]);
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions for a non-existent message.
|
||||
vector<int> numbers;
|
||||
EXPECT_FALSE(reverse_merged_.FindAllExtensionNumbers("Blah", &numbers));
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load diff
|
@ -1,558 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// DynamicMessage is implemented by constructing a data structure which
|
||||
// has roughly the same memory layout as a generated message would have.
|
||||
// Then, we use GeneratedMessageReflection to implement our reflection
|
||||
// interface. All the other operations we need to implement (e.g.
|
||||
// parsing, copying, etc.) are already implemented in terms of
|
||||
// Reflection, so the rest is easy.
|
||||
//
|
||||
// The up side of this strategy is that it's very efficient. We don't
|
||||
// need to use hash_maps or generic representations of fields. The
|
||||
// down side is that this is a low-level memory management hack which
|
||||
// can be tricky to get right.
|
||||
//
|
||||
// As mentioned in the header, we only expose a DynamicMessageFactory
|
||||
// publicly, not the DynamicMessage class itself. This is because
|
||||
// GenericMessageReflection wants to have a pointer to a "default"
|
||||
// copy of the class, with all fields initialized to their default
|
||||
// values. We only want to construct one of these per message type,
|
||||
// so DynamicMessageFactory stores a cache of default messages for
|
||||
// each type it sees (each unique Descriptor pointer). The code
|
||||
// refers to the "default" copy of the class as the "prototype".
|
||||
//
|
||||
// Note on memory allocation: This module often calls "operator new()"
|
||||
// to allocate untyped memory, rather than calling something like
|
||||
// "new uint8[]". This is because "operator new()" means "Give me some
|
||||
// space which I can use as I please." while "new uint8[]" means "Give
|
||||
// me an array of 8-bit integers.". In practice, the later may return
|
||||
// a pointer that is not aligned correctly for general use. I believe
|
||||
// Item 8 of "More Effective C++" discusses this in more detail, though
|
||||
// I don't have the book on me right now so I'm not sure.
|
||||
|
||||
#include <algorithm>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/generated_message_util.h>
|
||||
#include <google/protobuf/generated_message_reflection.h>
|
||||
#include <google/protobuf/reflection_ops.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/extension_set.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
using internal::WireFormat;
|
||||
using internal::ExtensionSet;
|
||||
using internal::GeneratedMessageReflection;
|
||||
|
||||
|
||||
// ===================================================================
|
||||
// Some helper tables and functions...
|
||||
|
||||
namespace {
|
||||
|
||||
// Compute the byte size of the in-memory representation of the field.
|
||||
int FieldSpaceUsed(const FieldDescriptor* field) {
|
||||
typedef FieldDescriptor FD; // avoid line wrapping
|
||||
if (field->label() == FD::LABEL_REPEATED) {
|
||||
switch (field->cpp_type()) {
|
||||
case FD::CPPTYPE_INT32 : return sizeof(RepeatedField<int32 >);
|
||||
case FD::CPPTYPE_INT64 : return sizeof(RepeatedField<int64 >);
|
||||
case FD::CPPTYPE_UINT32 : return sizeof(RepeatedField<uint32 >);
|
||||
case FD::CPPTYPE_UINT64 : return sizeof(RepeatedField<uint64 >);
|
||||
case FD::CPPTYPE_DOUBLE : return sizeof(RepeatedField<double >);
|
||||
case FD::CPPTYPE_FLOAT : return sizeof(RepeatedField<float >);
|
||||
case FD::CPPTYPE_BOOL : return sizeof(RepeatedField<bool >);
|
||||
case FD::CPPTYPE_ENUM : return sizeof(RepeatedField<int >);
|
||||
case FD::CPPTYPE_MESSAGE: return sizeof(RepeatedPtrField<Message>);
|
||||
|
||||
case FD::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
return sizeof(RepeatedPtrField<string>);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (field->cpp_type()) {
|
||||
case FD::CPPTYPE_INT32 : return sizeof(int32 );
|
||||
case FD::CPPTYPE_INT64 : return sizeof(int64 );
|
||||
case FD::CPPTYPE_UINT32 : return sizeof(uint32 );
|
||||
case FD::CPPTYPE_UINT64 : return sizeof(uint64 );
|
||||
case FD::CPPTYPE_DOUBLE : return sizeof(double );
|
||||
case FD::CPPTYPE_FLOAT : return sizeof(float );
|
||||
case FD::CPPTYPE_BOOL : return sizeof(bool );
|
||||
case FD::CPPTYPE_ENUM : return sizeof(int );
|
||||
case FD::CPPTYPE_MESSAGE: return sizeof(Message*);
|
||||
|
||||
case FD::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
return sizeof(string*);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GOOGLE_LOG(DFATAL) << "Can't get here.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int DivideRoundingUp(int i, int j) {
|
||||
return (i + (j - 1)) / j;
|
||||
}
|
||||
|
||||
static const int kSafeAlignment = sizeof(uint64);
|
||||
|
||||
inline int AlignTo(int offset, int alignment) {
|
||||
return DivideRoundingUp(offset, alignment) * alignment;
|
||||
}
|
||||
|
||||
// Rounds the given byte offset up to the next offset aligned such that any
|
||||
// type may be stored at it.
|
||||
inline int AlignOffset(int offset) {
|
||||
return AlignTo(offset, kSafeAlignment);
|
||||
}
|
||||
|
||||
#define bitsizeof(T) (sizeof(T) * 8)
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
class DynamicMessage : public Message {
|
||||
public:
|
||||
struct TypeInfo {
|
||||
int size;
|
||||
int has_bits_offset;
|
||||
int unknown_fields_offset;
|
||||
int extensions_offset;
|
||||
|
||||
// Not owned by the TypeInfo.
|
||||
DynamicMessageFactory* factory; // The factory that created this object.
|
||||
const DescriptorPool* pool; // The factory's DescriptorPool.
|
||||
const Descriptor* type; // Type of this DynamicMessage.
|
||||
|
||||
// Warning: The order in which the following pointers are defined is
|
||||
// important (the prototype must be deleted *before* the offsets).
|
||||
scoped_array<int> offsets;
|
||||
scoped_ptr<const GeneratedMessageReflection> reflection;
|
||||
scoped_ptr<const DynamicMessage> prototype;
|
||||
};
|
||||
|
||||
DynamicMessage(const TypeInfo* type_info);
|
||||
~DynamicMessage();
|
||||
|
||||
// Called on the prototype after construction to initialize message fields.
|
||||
void CrossLinkPrototypes();
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
Message* New() const;
|
||||
|
||||
int GetCachedSize() const;
|
||||
void SetCachedSize(int size) const;
|
||||
|
||||
Metadata GetMetadata() const;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
|
||||
|
||||
inline bool is_prototype() const {
|
||||
return type_info_->prototype == this ||
|
||||
// If type_info_->prototype is NULL, then we must be constructing
|
||||
// the prototype now, which means we must be the prototype.
|
||||
type_info_->prototype == NULL;
|
||||
}
|
||||
|
||||
inline void* OffsetToPointer(int offset) {
|
||||
return reinterpret_cast<uint8*>(this) + offset;
|
||||
}
|
||||
inline const void* OffsetToPointer(int offset) const {
|
||||
return reinterpret_cast<const uint8*>(this) + offset;
|
||||
}
|
||||
|
||||
const TypeInfo* type_info_;
|
||||
|
||||
// TODO(kenton): Make this an atomic<int> when C++ supports it.
|
||||
mutable int cached_byte_size_;
|
||||
};
|
||||
|
||||
DynamicMessage::DynamicMessage(const TypeInfo* type_info)
|
||||
: type_info_(type_info),
|
||||
cached_byte_size_(0) {
|
||||
// We need to call constructors for various fields manually and set
|
||||
// default values where appropriate. We use placement new to call
|
||||
// constructors. If you haven't heard of placement new, I suggest Googling
|
||||
// it now. We use placement new even for primitive types that don't have
|
||||
// constructors for consistency. (In theory, placement new should be used
|
||||
// any time you are trying to convert untyped memory to typed memory, though
|
||||
// in practice that's not strictly necessary for types that don't have a
|
||||
// constructor.)
|
||||
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet;
|
||||
|
||||
if (type_info_->extensions_offset != -1) {
|
||||
new(OffsetToPointer(type_info_->extensions_offset)) ExtensionSet;
|
||||
}
|
||||
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(CPPTYPE, TYPE) \
|
||||
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
||||
if (!field->is_repeated()) { \
|
||||
new(field_ptr) TYPE(field->default_value_##TYPE()); \
|
||||
} else { \
|
||||
new(field_ptr) RepeatedField<TYPE>(); \
|
||||
} \
|
||||
break;
|
||||
|
||||
HANDLE_TYPE(INT32 , int32 );
|
||||
HANDLE_TYPE(INT64 , int64 );
|
||||
HANDLE_TYPE(UINT32, uint32);
|
||||
HANDLE_TYPE(UINT64, uint64);
|
||||
HANDLE_TYPE(DOUBLE, double);
|
||||
HANDLE_TYPE(FLOAT , float );
|
||||
HANDLE_TYPE(BOOL , bool );
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
if (!field->is_repeated()) {
|
||||
new(field_ptr) int(field->default_value_enum()->number());
|
||||
} else {
|
||||
new(field_ptr) RepeatedField<int>();
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
if (!field->is_repeated()) {
|
||||
if (is_prototype()) {
|
||||
new(field_ptr) const string*(&field->default_value_string());
|
||||
} else {
|
||||
string* default_value =
|
||||
*reinterpret_cast<string* const*>(
|
||||
type_info_->prototype->OffsetToPointer(
|
||||
type_info_->offsets[i]));
|
||||
new(field_ptr) string*(default_value);
|
||||
}
|
||||
} else {
|
||||
new(field_ptr) RepeatedPtrField<string>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: {
|
||||
if (!field->is_repeated()) {
|
||||
new(field_ptr) Message*(NULL);
|
||||
} else {
|
||||
new(field_ptr) RepeatedPtrField<Message>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DynamicMessage::~DynamicMessage() {
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
reinterpret_cast<UnknownFieldSet*>(
|
||||
OffsetToPointer(type_info_->unknown_fields_offset))->~UnknownFieldSet();
|
||||
|
||||
if (type_info_->extensions_offset != -1) {
|
||||
reinterpret_cast<ExtensionSet*>(
|
||||
OffsetToPointer(type_info_->extensions_offset))->~ExtensionSet();
|
||||
}
|
||||
|
||||
// We need to manually run the destructors for repeated fields and strings,
|
||||
// just as we ran their constructors in the the DynamicMessage constructor.
|
||||
// Additionally, if any singular embedded messages have been allocated, we
|
||||
// need to delete them, UNLESS we are the prototype message of this type,
|
||||
// in which case any embedded messages are other prototypes and shouldn't
|
||||
// be touched.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
|
||||
if (field->is_repeated()) {
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
|
||||
case FieldDescriptor::CPPTYPE_##UPPERCASE : \
|
||||
reinterpret_cast<RepeatedField<LOWERCASE>*>(field_ptr) \
|
||||
->~RepeatedField<LOWERCASE>(); \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, int32);
|
||||
HANDLE_TYPE( INT64, int64);
|
||||
HANDLE_TYPE(UINT32, uint32);
|
||||
HANDLE_TYPE(UINT64, uint64);
|
||||
HANDLE_TYPE(DOUBLE, double);
|
||||
HANDLE_TYPE( FLOAT, float);
|
||||
HANDLE_TYPE( BOOL, bool);
|
||||
HANDLE_TYPE( ENUM, int);
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
reinterpret_cast<RepeatedPtrField<string>*>(field_ptr)
|
||||
->~RepeatedPtrField<string>();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
|
||||
->~RepeatedPtrField<Message>();
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING: {
|
||||
string* ptr = *reinterpret_cast<string**>(field_ptr);
|
||||
if (ptr != &field->default_value_string()) {
|
||||
delete ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) &&
|
||||
!is_prototype()) {
|
||||
Message* message = *reinterpret_cast<Message**>(field_ptr);
|
||||
if (message != NULL) {
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicMessage::CrossLinkPrototypes() {
|
||||
// This should only be called on the prototype message.
|
||||
GOOGLE_CHECK(is_prototype());
|
||||
|
||||
DynamicMessageFactory* factory = type_info_->factory;
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
// Cross-link default messages.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
|
||||
!field->is_repeated()) {
|
||||
// For fields with message types, we need to cross-link with the
|
||||
// prototype for the field's type.
|
||||
// For singular fields, the field is just a pointer which should
|
||||
// point to the prototype.
|
||||
*reinterpret_cast<const Message**>(field_ptr) =
|
||||
factory->GetPrototypeNoLock(field->message_type());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Message* DynamicMessage::New() const {
|
||||
void* new_base = reinterpret_cast<uint8*>(operator new(type_info_->size));
|
||||
memset(new_base, 0, type_info_->size);
|
||||
return new(new_base) DynamicMessage(type_info_);
|
||||
}
|
||||
|
||||
int DynamicMessage::GetCachedSize() const {
|
||||
return cached_byte_size_;
|
||||
}
|
||||
|
||||
void DynamicMessage::SetCachedSize(int size) const {
|
||||
// This is theoretically not thread-compatible, but in practice it works
|
||||
// because if multiple threads write this simultaneously, they will be
|
||||
// writing the exact same value.
|
||||
cached_byte_size_ = size;
|
||||
}
|
||||
|
||||
Metadata DynamicMessage::GetMetadata() const {
|
||||
Metadata metadata;
|
||||
metadata.descriptor = type_info_->type;
|
||||
metadata.reflection = type_info_->reflection.get();
|
||||
return metadata;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
struct DynamicMessageFactory::PrototypeMap {
|
||||
typedef hash_map<const Descriptor*, const DynamicMessage::TypeInfo*> Map;
|
||||
Map map_;
|
||||
};
|
||||
|
||||
DynamicMessageFactory::DynamicMessageFactory()
|
||||
: pool_(NULL), delegate_to_generated_factory_(false),
|
||||
prototypes_(new PrototypeMap) {
|
||||
}
|
||||
|
||||
DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool)
|
||||
: pool_(pool), delegate_to_generated_factory_(false),
|
||||
prototypes_(new PrototypeMap) {
|
||||
}
|
||||
|
||||
DynamicMessageFactory::~DynamicMessageFactory() {
|
||||
for (PrototypeMap::Map::iterator iter = prototypes_->map_.begin();
|
||||
iter != prototypes_->map_.end(); ++iter) {
|
||||
delete iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) {
|
||||
MutexLock lock(&prototypes_mutex_);
|
||||
return GetPrototypeNoLock(type);
|
||||
}
|
||||
|
||||
const Message* DynamicMessageFactory::GetPrototypeNoLock(
|
||||
const Descriptor* type) {
|
||||
if (delegate_to_generated_factory_ &&
|
||||
type->file()->pool() == DescriptorPool::generated_pool()) {
|
||||
return MessageFactory::generated_factory()->GetPrototype(type);
|
||||
}
|
||||
|
||||
const DynamicMessage::TypeInfo** target = &prototypes_->map_[type];
|
||||
if (*target != NULL) {
|
||||
// Already exists.
|
||||
return (*target)->prototype.get();
|
||||
}
|
||||
|
||||
DynamicMessage::TypeInfo* type_info = new DynamicMessage::TypeInfo;
|
||||
*target = type_info;
|
||||
|
||||
type_info->type = type;
|
||||
type_info->pool = (pool_ == NULL) ? type->file()->pool() : pool_;
|
||||
type_info->factory = this;
|
||||
|
||||
// We need to construct all the structures passed to
|
||||
// GeneratedMessageReflection's constructor. This includes:
|
||||
// - A block of memory that contains space for all the message's fields.
|
||||
// - An array of integers indicating the byte offset of each field within
|
||||
// this block.
|
||||
// - A big bitfield containing a bit for each field indicating whether
|
||||
// or not that field is set.
|
||||
|
||||
// Compute size and offsets.
|
||||
int* offsets = new int[type->field_count()];
|
||||
type_info->offsets.reset(offsets);
|
||||
|
||||
// Decide all field offsets by packing in order.
|
||||
// We place the DynamicMessage object itself at the beginning of the allocated
|
||||
// space.
|
||||
int size = sizeof(DynamicMessage);
|
||||
size = AlignOffset(size);
|
||||
|
||||
// Next the has_bits, which is an array of uint32s.
|
||||
type_info->has_bits_offset = size;
|
||||
int has_bits_array_size =
|
||||
DivideRoundingUp(type->field_count(), bitsizeof(uint32));
|
||||
size += has_bits_array_size * sizeof(uint32);
|
||||
size = AlignOffset(size);
|
||||
|
||||
// The ExtensionSet, if any.
|
||||
if (type->extension_range_count() > 0) {
|
||||
type_info->extensions_offset = size;
|
||||
size += sizeof(ExtensionSet);
|
||||
size = AlignOffset(size);
|
||||
} else {
|
||||
// No extensions.
|
||||
type_info->extensions_offset = -1;
|
||||
}
|
||||
|
||||
// All the fields.
|
||||
for (int i = 0; i < type->field_count(); i++) {
|
||||
// Make sure field is aligned to avoid bus errors.
|
||||
int field_size = FieldSpaceUsed(type->field(i));
|
||||
size = AlignTo(size, min(kSafeAlignment, field_size));
|
||||
offsets[i] = size;
|
||||
size += field_size;
|
||||
}
|
||||
|
||||
// Add the UnknownFieldSet to the end.
|
||||
size = AlignOffset(size);
|
||||
type_info->unknown_fields_offset = size;
|
||||
size += sizeof(UnknownFieldSet);
|
||||
|
||||
// Align the final size to make sure no clever allocators think that
|
||||
// alignment is not necessary.
|
||||
size = AlignOffset(size);
|
||||
type_info->size = size;
|
||||
|
||||
// Allocate the prototype.
|
||||
void* base = operator new(size);
|
||||
memset(base, 0, size);
|
||||
DynamicMessage* prototype = new(base) DynamicMessage(type_info);
|
||||
type_info->prototype.reset(prototype);
|
||||
|
||||
// Construct the reflection object.
|
||||
type_info->reflection.reset(
|
||||
new GeneratedMessageReflection(
|
||||
type_info->type,
|
||||
type_info->prototype.get(),
|
||||
type_info->offsets.get(),
|
||||
type_info->has_bits_offset,
|
||||
type_info->unknown_fields_offset,
|
||||
type_info->extensions_offset,
|
||||
type_info->pool,
|
||||
this,
|
||||
type_info->size));
|
||||
|
||||
// Cross link prototypes.
|
||||
prototype->CrossLinkPrototypes();
|
||||
|
||||
return prototype;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,136 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Defines an implementation of Message which can emulate types which are not
|
||||
// known at compile-time.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
||||
#define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in other files.
|
||||
class Descriptor; // descriptor.h
|
||||
class DescriptorPool; // descriptor.h
|
||||
|
||||
// Constructs implementations of Message which can emulate types which are not
|
||||
// known at compile-time.
|
||||
//
|
||||
// Sometimes you want to be able to manipulate protocol types that you don't
|
||||
// know about at compile time. It would be nice to be able to construct
|
||||
// a Message object which implements the message type given by any arbitrary
|
||||
// Descriptor. DynamicMessage provides this.
|
||||
//
|
||||
// As it turns out, a DynamicMessage needs to construct extra
|
||||
// information about its type in order to operate. Most of this information
|
||||
// can be shared between all DynamicMessages of the same type. But, caching
|
||||
// this information in some sort of global map would be a bad idea, since
|
||||
// the cached information for a particular descriptor could outlive the
|
||||
// descriptor itself. To avoid this problem, DynamicMessageFactory
|
||||
// encapsulates this "cache". All DynamicMessages of the same type created
|
||||
// from the same factory will share the same support data. Any Descriptors
|
||||
// used with a particular factory must outlive the factory.
|
||||
class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
|
||||
public:
|
||||
// Construct a DynamicMessageFactory that will search for extensions in
|
||||
// the DescriptorPool in which the exendee is defined.
|
||||
DynamicMessageFactory();
|
||||
|
||||
// Construct a DynamicMessageFactory that will search for extensions in
|
||||
// the given DescriptorPool.
|
||||
//
|
||||
// DEPRECATED: Use CodedInputStream::SetExtensionRegistry() to tell the
|
||||
// parser to look for extensions in an alternate pool. However, note that
|
||||
// this is almost never what you want to do. Almost all users should use
|
||||
// the zero-arg constructor.
|
||||
DynamicMessageFactory(const DescriptorPool* pool);
|
||||
|
||||
~DynamicMessageFactory();
|
||||
|
||||
// Call this to tell the DynamicMessageFactory that if it is given a
|
||||
// Descriptor d for which:
|
||||
// d->file()->pool() == DescriptorPool::generated_pool(),
|
||||
// then it should delegate to MessageFactory::generated_factory() instead
|
||||
// of constructing a dynamic implementation of the message. In theory there
|
||||
// is no down side to doing this, so it may become the default in the future.
|
||||
void SetDelegateToGeneratedFactory(bool enable) {
|
||||
delegate_to_generated_factory_ = enable;
|
||||
}
|
||||
|
||||
// implements MessageFactory ---------------------------------------
|
||||
|
||||
// Given a Descriptor, constructs the default (prototype) Message of that
|
||||
// type. You can then call that message's New() method to construct a
|
||||
// mutable message of that type.
|
||||
//
|
||||
// Calling this method twice with the same Descriptor returns the same
|
||||
// object. The returned object remains property of the factory and will
|
||||
// be destroyed when the factory is destroyed. Also, any objects created
|
||||
// by calling the prototype's New() method share some data with the
|
||||
// prototype, so these must be destoyed before the DynamicMessageFactory
|
||||
// is destroyed.
|
||||
//
|
||||
// The given descriptor must outlive the returned message, and hence must
|
||||
// outlive the DynamicMessageFactory.
|
||||
//
|
||||
// The method is thread-safe.
|
||||
const Message* GetPrototype(const Descriptor* type);
|
||||
|
||||
private:
|
||||
const DescriptorPool* pool_;
|
||||
bool delegate_to_generated_factory_;
|
||||
|
||||
// This struct just contains a hash_map. We can't #include <google/protobuf/stubs/hash.h> from
|
||||
// this header due to hacks needed for hash_map portability in the open source
|
||||
// release. Namely, stubs/hash.h, which defines hash_map portably, is not a
|
||||
// public header (for good reason), but dynamic_message.h is, and public
|
||||
// headers may only #include other public headers.
|
||||
struct PrototypeMap;
|
||||
scoped_ptr<PrototypeMap> prototypes_;
|
||||
mutable Mutex prototypes_mutex_;
|
||||
|
||||
friend class DynamicMessage;
|
||||
const Message* GetPrototypeNoLock(const Descriptor* type);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
|
@ -1,162 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Since the reflection interface for DynamicMessage is implemented by
|
||||
// GenericMessageReflection, the only thing we really have to test is
|
||||
// that DynamicMessage correctly sets up the information that
|
||||
// GenericMessageReflection needs to use. So, we focus on that in this
|
||||
// test. Other tests, such as generic_message_reflection_unittest and
|
||||
// reflection_ops_unittest, cover the rest of the functionality used by
|
||||
// DynamicMessage.
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/test_util.h>
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
class DynamicMessageTest : public testing::Test {
|
||||
protected:
|
||||
DescriptorPool pool_;
|
||||
DynamicMessageFactory factory_;
|
||||
const Descriptor* descriptor_;
|
||||
const Message* prototype_;
|
||||
const Descriptor* extensions_descriptor_;
|
||||
const Message* extensions_prototype_;
|
||||
const Descriptor* packed_descriptor_;
|
||||
const Message* packed_prototype_;
|
||||
|
||||
DynamicMessageTest(): factory_(&pool_) {}
|
||||
|
||||
virtual void SetUp() {
|
||||
// We want to make sure that DynamicMessage works (particularly with
|
||||
// extensions) even if we use descriptors that are *not* from compiled-in
|
||||
// types, so we make copies of the descriptors for unittest.proto and
|
||||
// unittest_import.proto.
|
||||
FileDescriptorProto unittest_file;
|
||||
FileDescriptorProto unittest_import_file;
|
||||
|
||||
unittest::TestAllTypes::descriptor()->file()->CopyTo(&unittest_file);
|
||||
unittest_import::ImportMessage::descriptor()->file()->CopyTo(
|
||||
&unittest_import_file);
|
||||
|
||||
ASSERT_TRUE(pool_.BuildFile(unittest_import_file) != NULL);
|
||||
ASSERT_TRUE(pool_.BuildFile(unittest_file) != NULL);
|
||||
|
||||
descriptor_ = pool_.FindMessageTypeByName("protobuf_unittest.TestAllTypes");
|
||||
ASSERT_TRUE(descriptor_ != NULL);
|
||||
prototype_ = factory_.GetPrototype(descriptor_);
|
||||
|
||||
extensions_descriptor_ =
|
||||
pool_.FindMessageTypeByName("protobuf_unittest.TestAllExtensions");
|
||||
ASSERT_TRUE(extensions_descriptor_ != NULL);
|
||||
extensions_prototype_ = factory_.GetPrototype(extensions_descriptor_);
|
||||
|
||||
packed_descriptor_ =
|
||||
pool_.FindMessageTypeByName("protobuf_unittest.TestPackedTypes");
|
||||
ASSERT_TRUE(packed_descriptor_ != NULL);
|
||||
packed_prototype_ = factory_.GetPrototype(packed_descriptor_);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DynamicMessageTest, Descriptor) {
|
||||
// Check that the descriptor on the DynamicMessage matches the descriptor
|
||||
// passed to GetPrototype().
|
||||
EXPECT_EQ(prototype_->GetDescriptor(), descriptor_);
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, OnePrototype) {
|
||||
// Check that requesting the same prototype twice produces the same object.
|
||||
EXPECT_EQ(prototype_, factory_.GetPrototype(descriptor_));
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, Defaults) {
|
||||
// Check that all default values are set correctly in the initial message.
|
||||
TestUtil::ReflectionTester reflection_tester(descriptor_);
|
||||
reflection_tester.ExpectClearViaReflection(*prototype_);
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, IndependentOffsets) {
|
||||
// Check that all fields have independent offsets by setting each
|
||||
// one to a unique value then checking that they all still have those
|
||||
// unique values (i.e. they don't stomp each other).
|
||||
scoped_ptr<Message> message(prototype_->New());
|
||||
TestUtil::ReflectionTester reflection_tester(descriptor_);
|
||||
|
||||
reflection_tester.SetAllFieldsViaReflection(message.get());
|
||||
reflection_tester.ExpectAllFieldsSetViaReflection(*message);
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, Extensions) {
|
||||
// Check that extensions work.
|
||||
scoped_ptr<Message> message(extensions_prototype_->New());
|
||||
TestUtil::ReflectionTester reflection_tester(extensions_descriptor_);
|
||||
|
||||
reflection_tester.SetAllFieldsViaReflection(message.get());
|
||||
reflection_tester.ExpectAllFieldsSetViaReflection(*message);
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, PackedFields) {
|
||||
// Check that packed fields work properly.
|
||||
scoped_ptr<Message> message(packed_prototype_->New());
|
||||
TestUtil::ReflectionTester reflection_tester(packed_descriptor_);
|
||||
|
||||
reflection_tester.SetPackedFieldsViaReflection(message.get());
|
||||
reflection_tester.ExpectPackedFieldsSetViaReflection(*message);
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, SpaceUsed) {
|
||||
// Test that SpaceUsed() works properly
|
||||
|
||||
// Since we share the implementation with generated messages, we don't need
|
||||
// to test very much here. Just make sure it appears to be working.
|
||||
|
||||
scoped_ptr<Message> message(prototype_->New());
|
||||
TestUtil::ReflectionTester reflection_tester(descriptor_);
|
||||
|
||||
int initial_space_used = message->SpaceUsed();
|
||||
|
||||
reflection_tester.SetAllFieldsViaReflection(message.get());
|
||||
EXPECT_LT(initial_space_used, message->SpaceUsed());
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue