From fa277052a9000dd07eb76fdc48d1280e1476bcd9 Mon Sep 17 00:00:00 2001 From: wangyingfang <132874950+wangyingfang@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:56:30 +0800 Subject: [PATCH 01/12] Add bold support for CJK characters (#3069) Co-authored-by: Yingfang Co-authored-by: Bart Louwers --- platform/darwin/src/local_glyph_rasterizer.mm | 31 +++++++- .../ping_fang_with_bold_in_style/expected.png | Bin 0 -> 17912 bytes test/text/local_glyph_rasterizer.test.cpp | 69 ++++++------------ 3 files changed, 48 insertions(+), 52 deletions(-) create mode 100644 test/fixtures/local_glyphs/ping_fang_with_bold_in_style/expected.png diff --git a/platform/darwin/src/local_glyph_rasterizer.mm b/platform/darwin/src/local_glyph_rasterizer.mm index 889b1daaadf..eef0bc31d4c 100644 --- a/platform/darwin/src/local_glyph_rasterizer.mm +++ b/platform/darwin/src/local_glyph_rasterizer.mm @@ -1,8 +1,11 @@ #include #include +#include #include #include +#include + #include #import @@ -191,16 +194,28 @@ CFDictionaryRefHandle attributes( @param font The font to apply to the codepoint. @param metrics Upon return, the metrics match the font’s metrics for the glyph representing the codepoint. + @param isBold use kCTFontBoldTrait if it is true. @returns An image containing the glyph. */ -PremultipliedImage drawGlyphBitmap(GlyphID glyphID, CTFontRef font, GlyphMetrics& metrics) { +PremultipliedImage drawGlyphBitmap(GlyphID glyphID, CTFontRef font, GlyphMetrics& metrics, BOOL isBold) { CFStringRefHandle string(CFStringCreateWithCharacters(NULL, reinterpret_cast(&glyphID), 1)); if (!string) { throw std::runtime_error("Unable to create string from codepoint"); } + // Create a bold variant of the font + CTFontRefHandle boldFont(CTFontCreateCopyWithSymbolicTraits(font, 0.0, NULL, kCTFontBoldTrait, kCTFontBoldTrait)); + if (!boldFont) { + CFStringRefHandle familyNameHandle(CTFontCopyFamilyName(font)); + NSString* familyName = (__bridge NSString *)(*familyNameHandle); + std::string stdFamilyName(familyName.UTF8String); + Log::Error(Event::General, "Unable to create bold font for " + stdFamilyName); + } + + CTFontRef drawFont = isBold && boldFont ? *boldFont : font; + CFStringRef keys[] = { kCTFontAttributeName }; - CFTypeRef values[] = { font }; + CFTypeRef values[] = { drawFont }; CFDictionaryRefHandle attributes( CFDictionaryCreate(kCFAllocatorDefault, (const void**)&keys, @@ -265,7 +280,7 @@ CGContextHandle context(CGBitmapContextCreate( CGContextSetTextPosition(*context, 0.0, descent); CTLineDraw(*line, *context); - + return rgbaBitmap; } @@ -288,8 +303,16 @@ CGContextHandle context(CGBitmapContextCreate( } manufacturedGlyph.id = glyphID; + BOOL isBold = NO; + // Only check the first font name to detect if the user prefers using bold + if (!fontStack.empty()) { + std::string lowercaseFont = platform::lowercase(fontStack.front()); + if (lowercaseFont.find("bold") != std::string::npos && lowercaseFont.find("semibold") == std::string::npos) { + isBold = YES; + } + } - PremultipliedImage rgbaBitmap = drawGlyphBitmap(glyphID, *font, manufacturedGlyph.metrics); + PremultipliedImage rgbaBitmap = drawGlyphBitmap(glyphID, *font, manufacturedGlyph.metrics, isBold); Size size(manufacturedGlyph.metrics.width, manufacturedGlyph.metrics.height); // Copy alpha values from RGBA bitmap into the AlphaImage output diff --git a/test/fixtures/local_glyphs/ping_fang_with_bold_in_style/expected.png b/test/fixtures/local_glyphs/ping_fang_with_bold_in_style/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..3de939b478752519d15009b0e599214f22765010 GIT binary patch literal 17912 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 M)78&qol`;+05dZGSO5S3 literal 0 HcmV?d00001 diff --git a/test/text/local_glyph_rasterizer.test.cpp b/test/text/local_glyph_rasterizer.test.cpp index 8e3235791c5..1922aacd97c 100644 --- a/test/text/local_glyph_rasterizer.test.cpp +++ b/test/text/local_glyph_rasterizer.test.cpp @@ -10,6 +10,8 @@ #include #include +#include + /* LoadLocalCJKGlyph in glyph_manager.test.cpp exercises the platform-independent part of LocalGlyphRasterizer. This test actually @@ -17,13 +19,8 @@ on. Different platforms have different default fonts, so adding a new platform requires new "expected" fixtures. - At the time of writing, we don't run `mbgl-test` on iOS or Android, so the - only supported test platform is macOS. Supporting Android would require - adding a new test case (probably using the "Droid" font family). iOS should - theoretically work -- the "PingFang" font family used below is expected to be - available on all iOS devices, and we use a relatively high image diff - tolerance (0.05) to account for small changes between the many possible - variants of the PingFang family. + At the time of writing, we don't run this test on Android, that would require + adding a new test case (probably using the "Droid" font family). */ using namespace mbgl; @@ -33,7 +30,14 @@ namespace { class LocalGlyphRasterizerTest { public: LocalGlyphRasterizerTest(const std::optional fontFamily) - : frontend(1, gfx::HeadlessBackend::SwapBehaviour::NoFlush, gfx::ContextMode::Unique, fontFamily) {} + : frontend(1, gfx::HeadlessBackend::SwapBehaviour::NoFlush, gfx::ContextMode::Unique, fontFamily) { + this->fileSource->glyphsResponse = [&](const Resource& resource) { + EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); + Response response; + response.data = std::make_shared(util::read_file("test/fixtures/resources/glyphs.pbf")); + return response; + }; + } util::RunLoop loop; std::shared_ptr fileSource = std::make_shared(); @@ -59,12 +63,6 @@ class LocalGlyphRasterizerTest { TEST(LocalGlyphRasterizer, PingFang) { LocalGlyphRasterizerTest test(std::string("PingFang TC")); - test.fileSource->glyphsResponse = [&](const Resource& resource) { - EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); - Response response; - response.data = std::make_shared(util::read_file("test/fixtures/resources/glyphs.pbf")); - return response; - }; test.map.getStyle().loadJSON(util::read_file("test/fixtures/local_glyphs/mixed.json")); #if defined(__APPLE__) && !defined(__QT__) test.checkRendering("ping_fang", 0.0161); @@ -73,16 +71,19 @@ TEST(LocalGlyphRasterizer, PingFang) { #endif // defined(__APPLE__) } +TEST(LocalGlyphRasterizer, PingFangWithBoldInStyle) { + LocalGlyphRasterizerTest test(std::string("PingFang TC")); + std::stringstream ss; + ss << std::regex_replace( + util::read_file("test/fixtures/local_glyphs/mixed.json"), std::regex("NotoCJK"), "NotoCJK Bold"); + test.map.getStyle().loadJSON(ss.str()); + test.checkRendering("ping_fang_with_bold_in_style"); +} + #if !defined(__QT__) TEST(LocalGlyphRasterizer, PingFangSemibold) { LocalGlyphRasterizerTest test(std::string("PingFang TC Semibold")); - test.fileSource->glyphsResponse = [&](const Resource& resource) { - EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); - Response response; - response.data = std::make_shared(util::read_file("test/fixtures/resources/glyphs.pbf")); - return response; - }; test.map.getStyle().loadJSON(util::read_file("test/fixtures/local_glyphs/mixed.json")); test.checkRendering("ping_fang_semibold", 0.0161); } @@ -94,13 +95,6 @@ TEST(LocalGlyphRasterizer, PingFangSemibold) { TEST(LocalGlyphRasterizer, NotoSansCJK) { LocalGlyphRasterizerTest test(std::string("Noto Sans CJK KR Regular")); - test.fileSource->glyphsResponse = [&](const Resource& resource) { - EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); - Response response; - response.data = std::make_shared(util::read_file("test/fixtures/resources/glyphs.pbf")); - return response; - }; - test.map.getStyle().loadJSON(util::read_file("test/fixtures/local_glyphs/mixed.json")); test.checkRendering("noto_sans_cjk_kr_regular_qt"); } @@ -110,13 +104,6 @@ TEST(LocalGlyphRasterizer, NoLocal) { // Expectation: without any local fonts set, and without any CJK glyphs // provided, the output should just contain basic latin characters. LocalGlyphRasterizerTest test({}); - - test.fileSource->glyphsResponse = [&](const Resource& resource) { - EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); - Response response; - response.data = std::make_shared(util::read_file("test/fixtures/resources/glyphs.pbf")); - return response; - }; test.map.getStyle().loadJSON(util::read_file("test/fixtures/local_glyphs/mixed.json")); test.checkRendering("no_local", 0.001, 0.1); } @@ -126,13 +113,6 @@ TEST(LocalGlyphRasterizer, NoLocalWithContentInsets) { // center. Rendered text should be on the same offset and keep the same size // as with no offset. LocalGlyphRasterizerTest test({}); - - test.fileSource->glyphsResponse = [&](const Resource& resource) { - EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); - Response response; - response.data = std::make_shared(util::read_file("test/fixtures/resources/glyphs.pbf")); - return response; - }; auto viewSize = test.frontend.getSize(); test.map.getStyle().loadJSON(util::read_file("test/fixtures/local_glyphs/mixed.json")); @@ -149,13 +129,6 @@ TEST(LocalGlyphRasterizer, NoLocalWithContentInsetsAndPitch) { // center. Rendered text should be on the same offset and keep the same size // as with no offset. LocalGlyphRasterizerTest test({}); - - test.fileSource->glyphsResponse = [&](const Resource& resource) { - EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); - Response response; - response.data = std::make_shared(util::read_file("test/fixtures/resources/glyphs.pbf")); - return response; - }; auto viewSize = test.frontend.getSize(); test.map.getStyle().loadJSON(util::read_file("test/fixtures/local_glyphs/mixed.json")); From 2771d4ab5233ea85cdde6fdb0d0690563a9aec80 Mon Sep 17 00:00:00 2001 From: Bart Louwers Date: Mon, 16 Dec 2024 16:31:09 +0100 Subject: [PATCH 02/12] Release MapLibre iOS 6.9.0 (#3094) --- platform/ios/CHANGELOG.md | 6 ++++++ platform/ios/VERSION | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index b49b5c50003..65ce874aee7 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -4,6 +4,12 @@ MapLibre welcomes participation and contributions from everyone. Please read [`C ## main +## 6.9.0 + +- Batch up scheduling of deferred deletions ([#3030](https://github.com/maplibre/maplibre-native/pull/3030)). +- Remove `Pass3D` ([#3077](https://github.com/maplibre/maplibre-native/pull/3077)). +- Add bold support for CJK characters ([#3069](https://github.com/maplibre/maplibre-native/pull/3069)). + ## 6.8.1 - Update Bazel dependencies ([#3000](https://github.com/maplibre/maplibre-native/pull/3000)). diff --git a/platform/ios/VERSION b/platform/ios/VERSION index 23863d3def7..6a1fccf9303 100644 --- a/platform/ios/VERSION +++ b/platform/ios/VERSION @@ -1 +1 @@ -6.8.1 \ No newline at end of file +6.9.0 \ No newline at end of file From d60857edc7efd1f8e2ad886ac1acb771023ba614 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:13:37 +0100 Subject: [PATCH 03/12] Bump the github-actions group across 1 directory with 2 updates (#3093) --- .github/workflows/gh-pages-android-api.yml | 2 +- .github/workflows/gh-pages-android-examples.yml | 2 +- .github/workflows/gh-pages-cpp-api.yml | 2 +- .github/workflows/gh-pages-mdbook.yml | 2 +- .github/workflows/ios-ci.yml | 2 +- .github/workflows/windows-ci.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/gh-pages-android-api.yml b/.github/workflows/gh-pages-android-api.yml index abe4b3fc690..5f327f21091 100644 --- a/.github/workflows/gh-pages-android-api.yml +++ b/.github/workflows/gh-pages-android-api.yml @@ -26,7 +26,7 @@ jobs: run: ./gradlew dokkaGenerate - name: Deploy πŸš€ - uses: JamesIves/github-pages-deploy-action@v4.6.9 + uses: JamesIves/github-pages-deploy-action@v4.7.2 with: branch: gh-pages folder: platform/android/MapLibreAndroid/build/dokka/html diff --git a/.github/workflows/gh-pages-android-examples.yml b/.github/workflows/gh-pages-android-examples.yml index 5ebde8efcd0..090401df1a6 100644 --- a/.github/workflows/gh-pages-android-examples.yml +++ b/.github/workflows/gh-pages-android-examples.yml @@ -23,7 +23,7 @@ jobs: run: make mkdocs-build - name: Deploy πŸš€ - uses: JamesIves/github-pages-deploy-action@v4.6.9 + uses: JamesIves/github-pages-deploy-action@v4.7.2 with: branch: gh-pages folder: platform/android/site diff --git a/.github/workflows/gh-pages-cpp-api.yml b/.github/workflows/gh-pages-cpp-api.yml index f2e9efa39a5..1095e1fbad3 100644 --- a/.github/workflows/gh-pages-cpp-api.yml +++ b/.github/workflows/gh-pages-cpp-api.yml @@ -20,7 +20,7 @@ jobs: run: doxygen - name: Deploy πŸš€ - uses: JamesIves/github-pages-deploy-action@v4.6.9 + uses: JamesIves/github-pages-deploy-action@v4.7.2 with: branch: gh-pages folder: docs/doxygen/html diff --git a/.github/workflows/gh-pages-mdbook.yml b/.github/workflows/gh-pages-mdbook.yml index cb76f166427..1ebce477a66 100644 --- a/.github/workflows/gh-pages-mdbook.yml +++ b/.github/workflows/gh-pages-mdbook.yml @@ -41,7 +41,7 @@ jobs: name: book path: artifacts/book - name: Deploy - uses: JamesIves/github-pages-deploy-action@v4.6.9 + uses: JamesIves/github-pages-deploy-action@v4.7.2 with: branch: gh-pages folder: artifacts/book diff --git a/.github/workflows/ios-ci.yml b/.github/workflows/ios-ci.yml index 7310a6f3bb8..f838c023f09 100644 --- a/.github/workflows/ios-ci.yml +++ b/.github/workflows/ios-ci.yml @@ -201,7 +201,7 @@ jobs: - name: Deploy DocC documentation (main) πŸš€ if: github.ref == 'refs/heads/main' - uses: JamesIves/github-pages-deploy-action@v4.6.9 + uses: JamesIves/github-pages-deploy-action@v4.7.2 continue-on-error: true with: branch: gh-pages diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index d00231ebeba..4e3f479aae5 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -87,7 +87,7 @@ jobs: core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); - - uses: mozilla-actions/sccache-action@v0.0.6 + - uses: mozilla-actions/sccache-action@v0.0.7 - name: Initialize sccache run: | From a843410bb27b2ec39559b443549a194f6178ecce Mon Sep 17 00:00:00 2001 From: Bart Louwers Date: Mon, 16 Dec 2024 20:55:49 +0100 Subject: [PATCH 04/12] Specify Vulkan version needed in AndroidManifest.xml (#3095) --- .../MapLibreAndroid/src/drawable/AndroidManifest.xml | 6 ++++++ .../android/MapLibreAndroid/src/main/AndroidManifest.xml | 4 ---- .../android/MapLibreAndroid/src/vulkan/AndroidManifest.xml | 7 +++++++ 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 platform/android/MapLibreAndroid/src/drawable/AndroidManifest.xml create mode 100644 platform/android/MapLibreAndroid/src/vulkan/AndroidManifest.xml diff --git a/platform/android/MapLibreAndroid/src/drawable/AndroidManifest.xml b/platform/android/MapLibreAndroid/src/drawable/AndroidManifest.xml new file mode 100644 index 00000000000..6ea1b76300b --- /dev/null +++ b/platform/android/MapLibreAndroid/src/drawable/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/platform/android/MapLibreAndroid/src/main/AndroidManifest.xml b/platform/android/MapLibreAndroid/src/main/AndroidManifest.xml index d5e48eb75d0..e33d8ddcd70 100644 --- a/platform/android/MapLibreAndroid/src/main/AndroidManifest.xml +++ b/platform/android/MapLibreAndroid/src/main/AndroidManifest.xml @@ -1,8 +1,4 @@ - - diff --git a/platform/android/MapLibreAndroid/src/vulkan/AndroidManifest.xml b/platform/android/MapLibreAndroid/src/vulkan/AndroidManifest.xml new file mode 100644 index 00000000000..eb13ac34e2d --- /dev/null +++ b/platform/android/MapLibreAndroid/src/vulkan/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From c94864f1a9a742d09d4619ec6aa786bb46824cb0 Mon Sep 17 00:00:00 2001 From: Bart Louwers Date: Wed, 18 Dec 2024 15:18:35 +0100 Subject: [PATCH 05/12] Prepare MapLibre Android 11.7.1 release (#3097) --- .github/workflows/android-release.yml | 26 +++++-------------- platform/android/CHANGELOG.md | 15 +++++++++++ .../android/MapLibreAndroid/gradle.properties | 2 +- scripts/generate-changelog.mjs | 2 +- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/.github/workflows/android-release.yml b/.github/workflows/android-release.yml index 02fb0f71c7b..35594f091c8 100644 --- a/.github/workflows/android-release.yml +++ b/.github/workflows/android-release.yml @@ -5,7 +5,7 @@ on: jobs: build: - runs-on: ubuntu-24.04 + runs-on: MapLibre_Native_Ubuntu_24_04_x84_16_core defaults: run: working-directory: platform/android @@ -19,8 +19,6 @@ jobs: submodules: recursive fetch-depth: 0 - - run: echo "cmake.dir=$(dirname "$(dirname "$(command -v cmake)")")" >> local.properties - - uses: actions/setup-java@v4 with: distribution: "temurin" @@ -47,6 +45,7 @@ jobs: - name: Update version name run: | RELEASE_VERSION="$( git describe --tags --match=android-v*.*.* --abbrev=0 | sed 's/^android-v//' )" + echo version="$RELEASE_VERSION" >> "$GITHUB_ENV" echo "Latest version from tag: $RELEASE_VERSION" if [ -n "$RELEASE_VERSION" ]; then sed -i -e "s/^VERSION_NAME=.*/VERSION_NAME=${RELEASE_VERSION}/" MapLibreAndroid/gradle.properties @@ -60,17 +59,6 @@ jobs: RENDERER=vulkan make apackage RENDERER=drawable make apackage - - name: Build release Test App - run: | - MAPLIBRE_DEVELOPER_CONFIG_XML='${{ secrets.MAPLIBRE_DEVELOPER_CONFIG_XML }}' - if [ -n "${MAPLIBRE_DEVELOPER_CONFIG_XML}" ]; then - echo "${MAPLIBRE_DEVELOPER_CONFIG_XML}" > MapLibreAndroidTestApp/src/main/res/values/developer-config.xml - make android - else - echo "No secrets.MAPLIBRE_DEVELOPER_CONFIG_XML variable set, skipping apk build..." - fi - shell: bash - # create github release - name: Prepare release id: prepare_release @@ -81,15 +69,15 @@ jobs: echo version_tag="$( git describe --tags --match=android-v*.*.* --abbrev=0 )" >> "$GITHUB_OUTPUT" shell: bash - - name: Check if version is valid semver + - name: Check if version is pre-release id: check_version run: | - version_tag="${{ steps.prepare_release.outputs.version_tag }}" - if [[ $version_tag =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Valid semver: $version_tag" + version="${{ env.version }}" + if [[ $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Valid semver: $version" echo "prerelease=false" >> "$GITHUB_ENV" else - echo "Invalid semver: $version_tag" + echo "Invalid semver: $version" echo "prerelease=true" >> "$GITHUB_ENV" fi diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 2884391bf55..2bedb5be327 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog MapLibre Native for Android +## 11.7.1 + +> [!NOTE] +> We are now releasing OpenGL ES and Vulkan variants of MapLibre Android. See the [11.7.0 release notes](https://github.com/maplibre/maplibre-native/releases/tag/android-v11.7.0) for details. + +### ✨ Features and improvements + +- Batch up scheduling of deferred deletions ([#3030](https://github.com/maplibre/maplibre-native/pull/3030)). +- Specify Vulkan version needed in AndroidManifest.xml ([#3095](https://github.com/maplibre/maplibre-native/pull/3095)). + +### 🐞 Bug fixes + +- Remove `Pass3D` ([#3077](https://github.com/maplibre/maplibre-native/pull/3077)). + Fixes issue where filters applied to fill extrusion layers are not rendered unless a manual zoom is applied to the map ([#3039](https://github.com/maplibre/maplibre-native/issues/3039)). + ## 11.7.0 This release marks the official release of MapLibre Android with Vulkan support. [Vulkan](https://www.vulkan.org) is a modern graphics API which brings advantages such as improved performance, improved observability and better stability. Specifically, starting with this version we are releasing multiple versions of MapLibre Android: diff --git a/platform/android/MapLibreAndroid/gradle.properties b/platform/android/MapLibreAndroid/gradle.properties index 081f5a9742c..93fed717d85 100644 --- a/platform/android/MapLibreAndroid/gradle.properties +++ b/platform/android/MapLibreAndroid/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=11.7.0 +VERSION_NAME=11.7.1 # Only build native dependencies for the current ABI # See https://code.google.com/p/android/issues/detail?id=221098#c20 diff --git a/scripts/generate-changelog.mjs b/scripts/generate-changelog.mjs index a704b8dcd3f..c18ed107318 100755 --- a/scripts/generate-changelog.mjs +++ b/scripts/generate-changelog.mjs @@ -18,7 +18,7 @@ function getTagLastVersion() { const lastVersion = fs .readFileSync(`platform/${platform}/CHANGELOG.md`, "utf-8") .split("\n") - .filter((line) => line.startsWith("## "))[1] + .filter((line) => line.startsWith("## "))[0] .slice(3); return `${platform}-v${lastVersion}`; } From b7bf48683cee22a35363e9a310893eb6b47c1a57 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 21:55:39 +0100 Subject: [PATCH 06/12] chore(deps): update dependency gradle to v8.12 (#3102) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- benchmark/android/gradle/wrapper/gradle-wrapper.properties | 2 +- benchmark/android/gradlew | 3 +-- .../MapLibrePlugin/gradle/wrapper/gradle-wrapper.properties | 2 +- platform/android/MapLibrePlugin/gradlew | 3 +-- platform/android/gradle/wrapper/gradle-wrapper.properties | 2 +- render-test/android/gradle/wrapper/gradle-wrapper.properties | 2 +- render-test/android/gradlew | 3 +-- test/android/gradle/wrapper/gradle-wrapper.properties | 2 +- test/android/gradlew | 3 +-- 9 files changed, 9 insertions(+), 13 deletions(-) diff --git a/benchmark/android/gradle/wrapper/gradle-wrapper.properties b/benchmark/android/gradle/wrapper/gradle-wrapper.properties index c1d5e018598..e0fd02028bc 100644 --- a/benchmark/android/gradle/wrapper/gradle-wrapper.properties +++ b/benchmark/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/benchmark/android/gradlew b/benchmark/android/gradlew index f5feea6d6b1..f3b75f3b0d4 100755 --- a/benchmark/android/gradlew +++ b/benchmark/android/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/platform/android/MapLibrePlugin/gradle/wrapper/gradle-wrapper.properties b/platform/android/MapLibrePlugin/gradle/wrapper/gradle-wrapper.properties index e2847c82004..cea7a793a84 100644 --- a/platform/android/MapLibrePlugin/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/MapLibrePlugin/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/platform/android/MapLibrePlugin/gradlew b/platform/android/MapLibrePlugin/gradlew index f5feea6d6b1..f3b75f3b0d4 100755 --- a/platform/android/MapLibrePlugin/gradlew +++ b/platform/android/MapLibrePlugin/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties index e2847c82004..cea7a793a84 100644 --- a/platform/android/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/render-test/android/gradle/wrapper/gradle-wrapper.properties b/render-test/android/gradle/wrapper/gradle-wrapper.properties index c1d5e018598..e0fd02028bc 100644 --- a/render-test/android/gradle/wrapper/gradle-wrapper.properties +++ b/render-test/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/render-test/android/gradlew b/render-test/android/gradlew index f5feea6d6b1..f3b75f3b0d4 100755 --- a/render-test/android/gradlew +++ b/render-test/android/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/test/android/gradle/wrapper/gradle-wrapper.properties b/test/android/gradle/wrapper/gradle-wrapper.properties index c1d5e018598..e0fd02028bc 100644 --- a/test/android/gradle/wrapper/gradle-wrapper.properties +++ b/test/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/test/android/gradlew b/test/android/gradlew index f5feea6d6b1..f3b75f3b0d4 100755 --- a/test/android/gradlew +++ b/test/android/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum From 8023e6dd3b8fe6cd149a1cf41ae51b13fe45bb39 Mon Sep 17 00:00:00 2001 From: Kiril Kirov Date: Sun, 29 Dec 2024 18:04:44 -0700 Subject: [PATCH 07/12] Add optional map mode argument to render (#3109) --- bin/render.cpp | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/bin/render.cpp b/bin/render.cpp index 26e1fa11ba0..6520f7baff1 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -38,6 +38,9 @@ int main(int argc, char* argv[]) { args::ValueFlag widthValue(argumentParser, "pixels", "Image width", {'w', "width"}); args::ValueFlag heightValue(argumentParser, "pixels", "Image height", {'h', "height"}); + args::ValueFlag mapModeValue( + argumentParser, "MapMode", "Map mode (e.g. 'static', 'tile', 'continuous')", {'m', "mode"}); + try { argumentParser.ParseCLI(argc, argv); } catch (const args::Help&) { @@ -79,18 +82,26 @@ int main(int argc, char* argv[]) { util::RunLoop loop; + MapMode mapMode = MapMode::Static; + if (mapModeValue) { + const auto modeStr = args::get(mapModeValue); + if (modeStr == "tile") { + mapMode = MapMode::Tile; + } else if (modeStr == "continuous") { + mapMode = MapMode::Continuous; + } + } + HeadlessFrontend frontend({width, height}, static_cast(pixelRatio)); - Map map(frontend, - MapObserver::nullObserver(), - MapOptions() - .withMapMode(MapMode::Static) - .withSize(frontend.getSize()) - .withPixelRatio(static_cast(pixelRatio)), - ResourceOptions() - .withCachePath(cache_file) - .withAssetPath(asset_root) - .withApiKey(apikey) - .withTileServerOptions(mapTilerConfiguration)); + Map map( + frontend, + MapObserver::nullObserver(), + MapOptions().withMapMode(mapMode).withSize(frontend.getSize()).withPixelRatio(static_cast(pixelRatio)), + ResourceOptions() + .withCachePath(cache_file) + .withAssetPath(asset_root) + .withApiKey(apikey) + .withTileServerOptions(mapTilerConfiguration)); if (style.find("://") == std::string::npos) { style = std::string("file://") + style; From 525a313153b212c0b7fb824bc6fc695386947c6e Mon Sep 17 00:00:00 2001 From: wangyingfang <132874950+wangyingfang@users.noreply.github.com> Date: Mon, 30 Dec 2024 20:19:18 +0800 Subject: [PATCH 08/12] Fix icon label isn't centered with the icon for CJK/local glyphy on iOS (#3108) Co-authored-by: Yingfang --- platform/darwin/src/local_glyph_rasterizer.mm | 2 +- .../local_glyphs/ping_fang/expected.png | Bin 18207 -> 17747 bytes .../ping_fang_semibold/expected.png | Bin 18500 -> 18279 bytes .../ping_fang_with_bold_in_style/expected.png | Bin 17912 -> 17875 bytes 4 files changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/darwin/src/local_glyph_rasterizer.mm b/platform/darwin/src/local_glyph_rasterizer.mm index eef0bc31d4c..4aa09548804 100644 --- a/platform/darwin/src/local_glyph_rasterizer.mm +++ b/platform/darwin/src/local_glyph_rasterizer.mm @@ -272,7 +272,7 @@ CGContextHandle context(CGBitmapContextCreate( // Mimic glyph PBF metrics. metrics.left = Glyph::borderSize; - metrics.top = 4; + metrics.top = -Glyph::borderSize; // Move the text upward to avoid clipping off descenders. CGFloat descent; diff --git a/test/fixtures/local_glyphs/ping_fang/expected.png b/test/fixtures/local_glyphs/ping_fang/expected.png index 0284836130450d01b88a9bb3d30f8b6a14ddd11e..9bb78c9f756cb0175d9ff7b98c154ff53428ab80 100644 GIT binary patch literal 17747 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 TUG6am(80EcL~gAK=H~tfKYAAZ literal 18500 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 M)78&qol`;+05dZGSO5S3 From ccd80c5adec34602814f3c4cc8830133c707f121 Mon Sep 17 00:00:00 2001 From: Justin Clift Date: Fri, 3 Jan 2025 00:47:13 +1000 Subject: [PATCH 09/12] Fix broken .geojson url (#3111) --- .../android/testapp/activity/style/HeatmapLayerActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/style/HeatmapLayerActivity.kt b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/style/HeatmapLayerActivity.kt index 117346e5694..cabaaabcd22 100644 --- a/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/style/HeatmapLayerActivity.kt +++ b/platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/style/HeatmapLayerActivity.kt @@ -192,7 +192,7 @@ class HeatmapLayerActivity : AppCompatActivity() { // # --8<-- [start:constants] companion object { private const val EARTHQUAKE_SOURCE_URL = - "https://maplibre.org/maplibre-gl-js-docs/assets/earthquakes.geojson" + "https://maplibre.org/maplibre-gl-js/docs/assets/earthquakes.geojson" private const val EARTHQUAKE_SOURCE_ID = "earthquakes" private const val HEATMAP_LAYER_ID = "earthquakes-heat" private const val HEATMAP_LAYER_SOURCE = "earthquakes" From 0efd06c3f0fa690d375a120985a046e67cd613f5 Mon Sep 17 00:00:00 2001 From: Sargun Vohra Date: Fri, 3 Jan 2025 05:50:19 -0800 Subject: [PATCH 10/12] Fix readme typo (#3113) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0daf7868cf4..26df2071c1f 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,7 @@ xed platform/ios/MapLibre.xcodeproj To generate and open the Xcode project. -More information: [`platform/android/CONTRIBUTING.md`](platform/ios/CONTRIBUTING.md). +More information: [`platform/ios/CONTRIBUTING.md`](platform/ios/CONTRIBUTING.md). ## Other Platforms From 660f78c583b40bead56abc0b2c3b9a41538db702 Mon Sep 17 00:00:00 2001 From: Bart Louwers Date: Sat, 4 Jan 2025 20:49:18 +0100 Subject: [PATCH 11/12] Use bazel_dep for libuv (#3114) --- MODULE.bazel | 11 ++--------- vendor/libuv.BUILD | 6 ------ 2 files changed, 2 insertions(+), 15 deletions(-) delete mode 100644 vendor/libuv.BUILD diff --git a/MODULE.bazel b/MODULE.bazel index fc8010bcf7c..3cdd4ed1335 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -8,6 +8,7 @@ bazel_dep(name = "rules_swift", version = "2.2.3", repo_name = "build_bazel_rule bazel_dep(name = "rules_xcodeproj", version = "2.8.1") bazel_dep(name = "aspect_rules_js", version = "2.1.0") bazel_dep(name = "rules_nodejs", version = "6.3.2") +bazel_dep(name = "libuv", version = "1.48.0") node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node", dev_dependency = True) node.toolchain(node_version = "20.14.0") @@ -54,16 +55,8 @@ http_archive( urls = ["https://github.com/glfw/glfw/releases/download/3.4/glfw-3.4.zip"], ) -new_local_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:local.bzl", "new_local_repository") - -new_local_repository( - name = "libuv", - build_file = "@//vendor:libuv.BUILD", - path = "/opt/homebrew/opt/libuv", -) - darwin_config = use_repo_rule("//platform/darwin:bazel/darwin_config_repository_rule.bzl", "darwin_config") darwin_config( name = "darwin_config", -) +) \ No newline at end of file diff --git a/vendor/libuv.BUILD b/vendor/libuv.BUILD deleted file mode 100644 index f37a18d41ae..00000000000 --- a/vendor/libuv.BUILD +++ /dev/null @@ -1,6 +0,0 @@ -cc_library( - name = "libuv", - hdrs = glob(["include/**/*.h"]), - includes = ["include"], - visibility = ["//visibility:public"], -) From c7e6b0c796ed047e6c0cf8d24e8b9768c5a39eff Mon Sep 17 00:00:00 2001 From: Bart Louwers Date: Mon, 6 Jan 2025 20:16:49 +0100 Subject: [PATCH 12/12] Consolidate developer documentation in mdBook docs (#3115) --- docs/mdbook/README.md | 6 +- docs/mdbook/book.toml | 4 +- docs/mdbook/src/SUMMARY.md | 24 +++-- .../mdbook/src/android/README.md | 39 +------- .../src/android/android-documentation.md | 49 ++++++++++ docs/mdbook/src/android/android-tests.md | 91 ++++++++++++++++++ docs/mdbook/src/design/README.md | 5 +- docs/mdbook/src/introduction.md | 2 + .../mdbook/src/ios/README.md | 92 +++---------------- docs/mdbook/src/ios/ios-documentation.md | 53 +++++++++++ docs/mdbook/src/ios/ios-tests.md | 18 ++++ docs/mdbook/src/platforms.md | 56 +++++++++++ platform/android/README.md | 10 +- platform/ios/README.md | 2 +- 14 files changed, 320 insertions(+), 131 deletions(-) rename platform/android/DEVELOPING.md => docs/mdbook/src/android/README.md (53%) create mode 100644 docs/mdbook/src/android/android-documentation.md create mode 100644 docs/mdbook/src/android/android-tests.md rename platform/ios/CONTRIBUTING.md => docs/mdbook/src/ios/README.md (55%) create mode 100644 docs/mdbook/src/ios/ios-documentation.md create mode 100644 docs/mdbook/src/ios/ios-tests.md create mode 100644 docs/mdbook/src/platforms.md diff --git a/docs/mdbook/README.md b/docs/mdbook/README.md index 268e1aec7f8..9e4a483131d 100644 --- a/docs/mdbook/README.md +++ b/docs/mdbook/README.md @@ -2,7 +2,11 @@ ## Build Locally -Get the `mdbook` utility, see https://rust-lang.github.io/mdBook/guide/installation.html +Get the `mdbook` utility as well as [`mdbook-alerts`](https://github.com/lambdalisue/rs-mdbook-alerts), see https://rust-lang.github.io/mdBook/guide/installation.html + +``` +cargo install mdbook mdbook-alerts +``` Run diff --git a/docs/mdbook/book.toml b/docs/mdbook/book.toml index 120536f1290..f68116e87f7 100644 --- a/docs/mdbook/book.toml +++ b/docs/mdbook/book.toml @@ -3,7 +3,9 @@ authors = ["MapLibre Contributors"] language = "en" multilingual = false src = "src" -title = "MapLibre Native Documentation" +title = "MapLibre Native Developer Documentation" [output.html] additional-css = ["diff.css"] + +[preprocessor.alerts] diff --git a/docs/mdbook/src/SUMMARY.md b/docs/mdbook/src/SUMMARY.md index ce37391c1c4..d07b042abd6 100644 --- a/docs/mdbook/src/SUMMARY.md +++ b/docs/mdbook/src/SUMMARY.md @@ -2,13 +2,23 @@ [Introduction](./introduction.md) +- [Platforms](./platforms.md) + +- [Android](./android/README.md) + - [Tests](./android/android-tests.md) + - [Documentation](./android/android-documentation.md) + +- [iOS](./ios/README.md) + - [Tests](ios/ios-tests.md) + - [Documentation](ios/ios-documentation.md) + - [Design](./design/README.md) - - [Ten Thousand Foot View](design/ten-thousand-foot-view.md) - - [Coordinate System](design/coordinate-system.md) - - [Expressions](design/expressions.md) - - [Architectural Problems and Recommendations](design/archictural-problems-and-recommendations.md) - - [Android Map Rendering Data Flow](design/android-map-rendering-data-flow.md) - - [Geometry Tile Worker](design/geometry-tile-worker.md) + - [Ten Thousand Foot View](design/ten-thousand-foot-view.md) + - [Coordinate System](design/coordinate-system.md) + - [Expressions](design/expressions.md) + - [Architectural Problems and Recommendations](design/archictural-problems-and-recommendations.md) + - [Android Map Rendering Data Flow](design/android-map-rendering-data-flow.md) + - [Geometry Tile Worker](design/geometry-tile-worker.md) - [Profiling applications that use MapLibre Native](./profiling/README.md) - - [Tracy profiling](./profiling/tracy-profiling.md) + - [Tracy profiling](./profiling/tracy-profiling.md) diff --git a/platform/android/DEVELOPING.md b/docs/mdbook/src/android/README.md similarity index 53% rename from platform/android/DEVELOPING.md rename to docs/mdbook/src/android/README.md index e8e19dd3e09..192d2f9ae25 100644 --- a/platform/android/DEVELOPING.md +++ b/docs/mdbook/src/android/README.md @@ -1,4 +1,4 @@ -# Developing - MapLibre Native for Android +# MapLibre Android Developer Guide These instructions are for developers interested in making code-level contributions to MapLibre Native for Android. @@ -33,34 +33,6 @@ Run the configuration for the `MapLibreAndroidTestApp` module and select a devic Android TestApp menu Android TestApp showing Demotiles

-## Render Tests - -To run the render tests for Android, run the configuration for the `androidRenderTest.app` module. - -More information on working on the render tests can be found [in the wiki](https://github.com/maplibre/maplibre-native/wiki/Working-on-Android-Render-Tests). - -## Instrumentation Tests - -To run the instrumentation tests, choose the "Instrumentation Tests" run configuration. - -Your device needs remain unlocked for the duration of the tests. - -## C++ Unit Tests - -There is a separate Gradle project that contains a test app which runs the C++ Unit Tests. It does not depend on the Android platform implementations. - -You can find the project in `test/android.` You can open this project in Android Studio and run the C++ Tests on an Android device or Simulator. - -To run a particular set of tests you can modify the `--gtest_filter` flag in `platform/android/src/test/test_runner.cpp`. See the [GoogleTest documentation](https://google.github.io/googletest/advanced.html#running-a-subset-of-the-tests) for details how to use this flag. - -### AWS Device Farm - -The instrumentation tests and C++ unit tests are running on AWS Device Farm. To see the results and the logs, go to: - -https://us-west-2.console.aws.amazon.com/devicefarm/home?region=us-east-1#/mobile/projects/20687d72-0e46-403e-8f03-0941850665bc/runs - -You can log in with the `maplibre` alias, with `maplibre` as username and `maplibre` as password (this is a read-only account). - ## Kotlin All new code should be written in [Kotlin](https://kotlinlang.org/). @@ -91,11 +63,4 @@ To run the benchmarks (for Android) include the following line on a PR comment: ## Profiling -[maplibre-native/docs/mdbook](https://maplibre.org/maplibre-native/docs/book/) describes how Tracy can be used for profiling. - - -## Documentation - -We use Dokka for the API documentation. - -The documentation site with examples uses MkDocs along with Material for MkDocs. For more information on how to work on the examples, see [`docs/README.md`](./docs/REAME.md`). \ No newline at end of file +See [Tracy Profiling](/profiling/tracy-profiling.md) to understand how Tracy can be used for profiling. \ No newline at end of file diff --git a/docs/mdbook/src/android/android-documentation.md b/docs/mdbook/src/android/android-documentation.md new file mode 100644 index 00000000000..26c0932b2e1 --- /dev/null +++ b/docs/mdbook/src/android/android-documentation.md @@ -0,0 +1,49 @@ +# Documentation for MapLibre Android + +## API Documentation + +We use Dokka for the MapLibre Android API documentation. The live documentation site can be found [here](https://maplibre.org/maplibre-native/android/api/). + +## Examples Documentation + +The documentation site with examples uses MkDocs along with [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/). You can check out the site [here](https://maplibre.org/maplibre-native/android/examples/). + +### Building + +To build the Examples Documentation you need to have Docker installed. + +From `platform/android`, run: + +``` +make mkdocs +``` + +Next, visit [`http://localhost:8000/maplibre-native/android/examples/`](http://localhost:8000/maplibre-native/android/examples/). + +### Snippets + +We use [a Markdown extension for snippets](https://facelessuser.github.io/pymdown-extensions/extensions/snippets/#snippet-sections). This way code can be referenced instead of copy pasted into the documentation. This avoids code examples from becoming out of date or failing to compile. The syntax is as follows: + +````kotlin +// --8<-- [start:fun] +fun double(x: Int): Int { + return 2 * x +} +// --8<-- [end:fun] +```` + +Next, you'll be able to reference that piece of code in Markdown like so: + +``` +--8<-- "example.kt:fun" +``` + +Where `example.kt` is the path to the file. + +### Static Assets + +Static assets are ideally uploaded to the [MapLibre Native S3 Bucket](https://maplibre-native.s3.eu-central-1.amazonaws.com/index.html#android-documentation-resources/). + +Please open an issue with the ARN of your AWS account to get upload privileges. + +You can use the macro `{{ s3_url("filename.example") }}` which will use a CDN instead of linking to the S3 bucket directly. \ No newline at end of file diff --git a/docs/mdbook/src/android/android-tests.md b/docs/mdbook/src/android/android-tests.md new file mode 100644 index 00000000000..6e7e971195a --- /dev/null +++ b/docs/mdbook/src/android/android-tests.md @@ -0,0 +1,91 @@ +# MapLibre Android Tests + +## Render Tests + +To run the render tests for Android, run the configuration for the `androidRenderTest.app` module. + +### Filtering Render Tests + +You can filter the tests to run by passing a flag to the file `platform/android/src/test/render_test_runner.cpp`: + +```cpp +std::vector arguments = {..., "-f", "background-color/literal"}; +``` + +### Viewing the Results + +Once the application quits, use the Device Explorer to navigate to `/data/data/org.maplibre.render_test_runner/files`. + +image + +Double click `android-render-test-runner-style.html`. Right click on the opened tab and select _Open In > Browser_. You should see that a single render test passed. + +image + +Alternatively to download (and open) the results from the command line, use: + +``` +adb shell "run-as org.maplibre.render_test_runner cat files/metrics/android-render-test-runner-style.html" > android-render-test-runner-style.html +open android-render-test-runner-style.html +``` + +### Updating the Render Tests + +Now let's edit `metrics/integration/render-tests/background-color/literal/style.json`, change this line: + +``` + "background-color": "red" +``` + +to + +``` + "background-color": "yellow" +``` + +We need to make sure that the new `data.zip` with the data for the render tests is installed on the device. You can use the following commands: + +``` +tar chf render-test/android/app/src/main/assets/data.zip --format=zip --files-from=render-test/android/app/src/main/assets/to_zip.txt +adb push render-test/android/app/src/main/assets/data.zip /data/local/tmp/data.zip +adb shell chmod 777 /data/local/tmp/data.zip +adb shell "run-as org.maplibre.render_test_runner unzip -o /data/local/tmp/data.zip -d files" +``` + +Rerun the render test app and reload the Device Explorer. When you re-open the HTML file with the results you should now see a failing test: + +image + +Now download the `actual.png` in `metrics/integration/render-tests/background-color/literal` with the Device Explorer. Replace the corresponding `expected.png` on your local file system. Upload the new render test data again and run the test app once more. + +image + +Of we don't want to commit this change. But know you can add and debug (Android) render tests. + +## Instrumentation Tests + +To run the instrumentation tests, choose the "Instrumentation Tests" run configuration. + +Your device needs remain unlocked for the duration of the tests. + +## C++ Unit Tests + +There is a separate Gradle project that contains a test app which runs the C++ Unit Tests. It does not depend on the Android platform implementations. + +You can find the project in `test/android.` You can open this project in Android Studio and run the C++ Tests on an Android device or Simulator. + +To run a particular set of tests you can modify the `--gtest_filter` flag in `platform/android/src/test/test_runner.cpp`. See the [GoogleTest documentation](https://google.github.io/googletest/advanced.html#running-a-subset-of-the-tests) for details how to use this flag. + +### AWS Device Farm + +The instrumentation tests and C++ unit tests are running on AWS Device Farm. To see the results and the logs, go to: + +[https://us-west-2.console.aws.amazon.com/devicefarm/home?region=us-east-1#/mobile/projects/20687d72-0e46-403e-8f03-0941850665bc/runs](https://us-west-2.console.aws.amazon.com/devicefarm/home?region=us-east-1#/mobile/projects/20687d72-0e46-403e-8f03-0941850665bc/runs). + +Use the following login details (this is a read-only account): + +| | | +|------------|------------| +| Alias | `maplibre` | +| Username | `maplibre` | +| Password | `maplibre` | diff --git a/docs/mdbook/src/design/README.md b/docs/mdbook/src/design/README.md index f4af5367d00..02dec693c00 100644 --- a/docs/mdbook/src/design/README.md +++ b/docs/mdbook/src/design/README.md @@ -1,3 +1,6 @@ +> [!NOTE] +> These notes are partially outdated since the [renderer modularization](https://github.com/maplibre/maplibre-native/blob/main/design-proposals/2022-10-27-rendering-modularization.md). + # Design -This section is dedicated to documenting current state of MapLibre Native. [Architectural Problems and Recommendations](./archictural-problems-and-recommendations.md) section notes recommendations for future improvements from an architectural perspective. +This section is dedicated to documenting current state of MapLibre Native as of end 2022. [Architectural Problems and Recommendations](./archictural-problems-and-recommendations.md) section notes recommendations for future improvements from an architectural perspective. diff --git a/docs/mdbook/src/introduction.md b/docs/mdbook/src/introduction.md index b7c27c66915..43db78c31c5 100644 --- a/docs/mdbook/src/introduction.md +++ b/docs/mdbook/src/introduction.md @@ -3,3 +3,5 @@ *[MapLibre Native](https://github.com/maplibre/maplibre-native)* is a community led fork of *Mapbox GL Native*. It's a C++ library that powers vector maps in native applications on multiple platforms by taking stylesheets that conform to the *[MapLibre Style Specification](https://maplibre.org/maplibre-style-spec/)*, a fork of the Mapbox Style Spec. Since it is derived from Mapbox's original work it also uses *Mapbox Vector Tile Specification* as its choice of vector tile format. + +This documentation is intended for developers of MapLibre Native. If you are interested in *using* MapLibre Native, check out the [main `README.md`](https://github.com/maplibre/maplibre-native?tab=readme-ov-file#maplibre-native) on GitHub. diff --git a/platform/ios/CONTRIBUTING.md b/docs/mdbook/src/ios/README.md similarity index 55% rename from platform/ios/CONTRIBUTING.md rename to docs/mdbook/src/ios/README.md index b17b955329c..208f34d3de3 100644 --- a/platform/ios/CONTRIBUTING.md +++ b/docs/mdbook/src/ios/README.md @@ -1,13 +1,4 @@ -# Contributing - -## Downloading Source - -Download the source and install all submodules if you have not already, by running the following from the root of the repository. - -``` -git clone --recurse-submodules git@github.com:maplibre/maplibre-native.git -cd maplibre-native -``` +# MapLibre iOS Developer Guide ## Bazel @@ -56,91 +47,32 @@ Try to run the example App in the simulator and on a device to confirm your setu > [!IMPORTANT] > The Bazel configuration files are the source of truth of the build configuration. All changes to the build settings need to be done through Bazel, not in Xcode. -### Troubleshooting Provisioning Profiles +### Troubleshooting + +#### Provisioning Profiles If you get a Python `KeyError` when processing provisioning profiles, you probably have some _really_ old or corrupted profiles. Have a look through `~/Library/MobileDevice/Provisioning\ Profiles` and remove any expired profiles. Removing all profiles here can also resolve some issues. -## Using Bazel from the Command Line +#### Cleaning Bazel environments -It is also possible to build and run the test application in a simulator from the command line without opening Xcode. +You should almost never have to do this, but sometimes problems can be solved with: ``` -bazel run //platform/ios:App --//:renderer=metal +bazel clean --expunge ``` -You can also build targets from the command line. For example, if you want to build your own XCFramework, see the 'Build XCFramework' step in the [iOS CI workflow](../../.github/workflows/ios-ci.yml). - -## Render Tests - -To run the render tests, run the `RenderTest` target from iOS. +## Using Bazel from the Command Line -When running in a simulator, use +It is also possible to build and run the test application in a simulator from the command line without opening Xcode. ``` -# check for 'DataContainer' of the app with `*.maplibre.RenderTestApp` id -xcrun simctl listapps booted +bazel run //platform/ios:App --//:renderer=metal ``` -to get the data directory of the render test app. This allows you to inspect test results. When adding new tests, the generated expectations and `actual.png` file can be copied into the source directory from here. - -## C++ Unit Tests - -Run the tests from the `CppUnitTests` target in Xcode to run the C++ Unit Tests on iOS. +You can also build targets from the command line. For example, if you want to build your own XCFramework, see the 'Build XCFramework' step in the [iOS CI workflow](../../.github/workflows/ios-ci.yml). ## Swift App -There is also an example app built with Swift instead of Objective-C. The target is called `MapLibreApp` and the source code lives in `platform/ios/app-swift`. - -## Documentation - -We use [DocC](https://www.swift.org/documentation/docc) for documentation. You need to have [aws-cli](https://github.com/aws/aws-cli) installed to download the resources from S3 (see below). Run the following command: - -``` -aws s3 sync --no-sign-request "s3://maplibre-native/ios-documentation-resources" "platform/ios/MapLibre.docc/Resources" -``` - -Then, to build the documentation locally, run the following command: - -``` -platform/ios/scripts/docc.sh preview -``` - -### Resources - -Resources like images should not be checked in but should be uploaded to the [S3 Bucket](https://s3.eu-central-1.amazonaws.com/maplibre-native/index.html#ios-documentation-resources/). You can share a `.zip` with all files that should be added in the PR. - -If you want to get direct access you need an AWS account to get permissions to upload files. Create an account and authenticate with aws-cli. Share the account ARN that you can get with - -``` -aws sts get-caller-identity -``` - -### Examples - -The code samples in the documentation should ideally be compiled on CI so they do not go out of date. - -Fence your example code with - -```swift -// #-example-code(LineTapMap) -... -// #-end-example-code -``` - -Prefix your documentation code block with - -````md - - -```swift -... -``` -```` - -Then the code block will be updated when you run: - -```sh -node scripts/update-ios-examples.mjs -``` +There is also an example app built with Swift instead of Objective-C. The target is called `MapLibreApp` and the source code lives in `platform/ios/app-swift`. \ No newline at end of file diff --git a/docs/mdbook/src/ios/ios-documentation.md b/docs/mdbook/src/ios/ios-documentation.md new file mode 100644 index 00000000000..bba85d1aa96 --- /dev/null +++ b/docs/mdbook/src/ios/ios-documentation.md @@ -0,0 +1,53 @@ +# iOS Documentation + +We use [DocC](https://www.swift.org/documentation/docc) for the MapLibre iOS documentation. The live documentation site can be found [here](https://maplibre.org/maplibre-native/ios/latest/documentation/maplibre/). + +## Resources + +You need to have [aws-cli](https://github.com/aws/aws-cli) installed to download the resources from S3 (see below). Run the following command: + +``` +aws s3 sync --no-sign-request "s3://maplibre-native/ios-documentation-resources" "platform/ios/MapLibre.docc/Resources" +``` + +Then, to build the documentation locally, run the following command: + +``` +platform/ios/scripts/docc.sh preview +``` + +Resources like images should not be checked in but should be uploaded to the [S3 Bucket](https://s3.eu-central-1.amazonaws.com/maplibre-native/index.html#ios-documentation-resources/). You can share a `.zip` with all files that should be added in the PR. + +If you want to get direct access you need an AWS account to get permissions to upload files. Create an account and authenticate with aws-cli. Share the account ARN that you can get with + +``` +aws sts get-caller-identity +``` + +## Examples + +The code samples in the documentation should ideally be compiled on CI so they do not go out of date. + +Fence your example code with + +```swift +// #-example-code(LineTapMap) +... +// #-end-example-code +``` + +Prefix your documentation code block with + +````md + + +```swift +... +``` +```` + +Then the code block will be updated when you run: + +```sh +node scripts/update-ios-examples.mjs +``` \ No newline at end of file diff --git a/docs/mdbook/src/ios/ios-tests.md b/docs/mdbook/src/ios/ios-tests.md new file mode 100644 index 00000000000..570f789ce7a --- /dev/null +++ b/docs/mdbook/src/ios/ios-tests.md @@ -0,0 +1,18 @@ +# iOS Tests + +## Render Tests + +To run the render tests, run the `RenderTest` target from iOS. + +When running in a simulator, use + +``` +# check for 'DataContainer' of the app with `*.maplibre.RenderTestApp` id +xcrun simctl listapps booted +``` + +to get the data directory of the render test app. This allows you to inspect test results. When adding new tests, the generated expectations and `actual.png` file can be copied into the source directory from here. + +## C++ Unit Tests + +Run the tests from the `CppUnitTests` target in Xcode to run the C++ Unit Tests on iOS. \ No newline at end of file diff --git a/docs/mdbook/src/platforms.md b/docs/mdbook/src/platforms.md new file mode 100644 index 00000000000..01b70ae8f8b --- /dev/null +++ b/docs/mdbook/src/platforms.md @@ -0,0 +1,56 @@ + +# Platforms + +This page describes the platforms that MapLibre Native is available on. + +## Overview + +MapLibre Native uses a monorepo. Source code for all platforms lives in [`maplibre/maplibre-native`](https://github.com/maplibre/maplibre-native) on GitHub. + +| Platform | Source | Notes | +|---|---|---| +| Android | [`platform/android`](https://github.com/maplibre/maplibre-native/tree/main/platform/android) | Integrates with the C++ core via JNI. | +| iOS | [`platform/ios`](https://github.com/maplibre/maplibre-native/tree/main/platform/ios), [`platform/darwin`](https://github.com/maplibre/maplibre-native/tree/main/platform/darwin) | Integrates with the C++ core via Objective-C++. | +| Linux | [`platform/linux`](https://github.com/maplibre/maplibre-native/tree/main/platform/linux) | Used for development. Also widely used in production for raster tile generation. | +| Windows | [`platform/windows`](https://github.com/maplibre/maplibre-native/tree/main/platform/windows) | | +| macOS | [`platform/macos`](https://github.com/maplibre/maplibre-native/tree/main/platform/macos), [`platform/darwin`](https://github.com/maplibre/maplibre-native/tree/main/platform/darwin) | Mainly used for development. There is some legacy AppKit code. | +| Node.js | [`platform/node`](https://github.com/maplibre/maplibre-native/tree/main/platform/node) | Uses [NAN](https://github.com/nodejs/nan). Available as [@maplibre/maplibre-gl-native](https://www.npmjs.com/package/@maplibre/maplibre-gl-native) on npm. | +| Qt | [maplibre/maplibre-qt](https://github.com/maplibre/maplibre-native/tree/main/platform/qt), [`platform/qt`](https://github.com/maplibre/maplibre-native) | Only platform that partially split to another repository. | + +Of these, **Android** and **iOS** are considered [core projects](https://github.com/maplibre/maplibre/blob/main/PROJECT_TIERS.md) of the MapLibre Organization. +### GLFW + +You can find an app that uses GLFW in [`platform/glfw`](https://github.com/maplibre/maplibre-native/tree/main/platform/glfw). It works on macOS, Linux and Windows. The app shows an interactive map that can be interacted with. Since GLFW adds relatively little complexity this app is used a lot for development. You can also learn about the C++ API by studying the source code of the GLFW app. + +## Rendering Backends + +Originally the project only supported OpenGL 2.0. In 2023, the [renderer was modularized](https://github.com/maplibre/maplibre-native/blob/main/design-proposals/2022-10-27-rendering-modularization.md) allowing for the implementation of alternate rendering backends. The first alternate rendering backend that was implemented was [Metal](https://maplibre.org/news/2024-01-19-metal-support-for-maplibre-native-ios-is-here/), followed by [Vulkan](https://maplibre.org/news/2024-12-12-maplibre-android-vulkan/). In the future other rendering backends could be implemented such as WebGPU. + +What platfroms support which rendering backend can be found below. + +| Platform | OpenGL ES 3.0 | Vulkan 1.0 | Metal | +|---|---|---|---| +| Android | βœ… | βœ… | ❌ | +| iOS | ❌ | ❌ | βœ… | +| Linux | βœ… | βœ… | ❌ | +| Windows | βœ… | ❌ | ❌ | +| macOS | ❌ | βœ… | βœ…[^1] | +| Node.js | βœ… | ❌ | βœ… [^2] | +| Qt | βœ… | ❌ | ❌ | + +[^1]: Requires MoltenVK. Only available when built via CMake. +[^2]: Issue reported, see [#2928](https://github.com/maplibre/maplibre-native/issues/2928). + +## Build Tooling + +In 2023 we co-opted Bazel as a build tool (generator), mostly due to it having better support for iOS compared to CMake. Some platforms can use CMake as well as Bazel. + +| Platform | CMake | Bazel | +|---|---|---| +| Android | βœ… (via Gradle) | ❌ | +| iOS | ❌ | βœ… | +| Linux | βœ… | βœ… | +| Windows | βœ… | ❌ | +| macOS | βœ… | βœ… | +| Node.js | βœ… | ❌ | +| Qt | βœ… | ❌ | diff --git a/platform/android/README.md b/platform/android/README.md index a68bd7ced96..029a598eee0 100644 --- a/platform/android/README.md +++ b/platform/android/README.md @@ -8,10 +8,14 @@ MapLibre Native for Android is a library for embedding interactive map views wit Visit [https://maplibre.org/maplibre-native/android/examples/getting-started/](https://maplibre.org/maplibre-native/android/examples/getting-started/) to view the Getting Started Guide for MapLibre Native for Android. -## Documentation +### Examples Documentation -Visit [https://maplibre.org/maplibre-native/android/api/](https://maplibre.org/maplibre-native/android/api/) to view the current API reference Javadoc files for MapLibre Native for Android. +Visit [MapLibre Android Example](https://maplibre.org/maplibre-native/android/examples/) to learn how to use MapLibre Android. + +## API Documentation + +Visit [MapLibre Android Dokka Docs](https://maplibre.org/maplibre-native/android/api/) to view the current API reference for MapLibre Android. ## Contributing -See [`DEVELOPING.md`](./DEVELOPING.md) for instructions on how to get started working on the codebase. +See the [MapLibre Android Developer Guide](https://maplibre.org/maplibre-native/docs/book/android) for instructions on how to build the project or how to work on the documentation. diff --git a/platform/ios/README.md b/platform/ios/README.md index 412ae58d2f2..51d906cc208 100644 --- a/platform/ios/README.md +++ b/platform/ios/README.md @@ -11,4 +11,4 @@ Embed interactive maps with scalable, customizable vector maps into iOS Applicat # Contributing -See [`CONTRIBUTING.md`](./CONTRIBUTING.md) for instructions on how to build the project or how to work on the documentation. +See the [MapLibre iOS Developer Guide](https://maplibre.org/maplibre-native/docs/book/ios) for instructions on how to build the project or how to work on the documentation.