Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c87f0e6
fix: fix ios build from source.
andycall Dec 21, 2025
2a0e98f
refactor: clean the examples
andycall Dec 21, 2025
a18b86b
fix: fix lint issues for cupertino ui.
andycall Dec 21, 2025
03606a6
fix: fix tailwindcss gradient color issue.
andycall Dec 21, 2025
d4e7a21
fix: disable the scrolling if the content were not expand the scroll …
andycall Dec 21, 2025
477462a
fix: fix over hidden still hoz scrollable.
andycall Dec 21, 2025
8be8b61
fix: fix gifs and data uri svg image loads.
andycall Dec 22, 2025
b2b2b60
fix: disable scrollbars for the listview.
andycall Dec 22, 2025
bc911b4
fix: fix release scripts.
andycall Dec 22, 2025
bb44894
fix: fix mount router view unexpected disposed the route view
andycall Dec 22, 2025
8c83d04
feat: use go_router for more robust routing.
andycall Dec 22, 2025
55b6398
fix: fix Hybrid Router maybePop api
andycall Dec 22, 2025
98997a5
feat: add support dynamic router for @openwebf/react-router
andycall Dec 22, 2025
e87bcf1
feat: fix svg and images showcases
andycall Dec 22, 2025
e426d34
feat: fix routing demos.
andycall Dec 22, 2025
4fa19fe
fix: fix typography showcases
andycall Dec 22, 2025
6675f9d
fix: fix currentRootViewport null error.
andycall Dec 23, 2025
a76394c
optimize: avoid checking the css property and value when resolved fro…
andycall Dec 23, 2025
0239fae
fix(css): resolve padding-inline-start/end by direction at layout time
andycall Dec 23, 2025
a99805b
fix(css): treat empty custom properties as empty tokens
andycall Dec 23, 2025
f2eadc4
fix(webf): honor transformed containing block for position: fixed
andycall Dec 24, 2025
510cfac
fix(webf): respect MediaQuery TextScaler/boldText across WebF + Rout…
andycall Dec 24, 2025
960a09c
feat: add scrollByIndex API for listview
andycall Dec 24, 2025
d4a72c3
fix(css): implement ch length unit resolution
andycall Dec 24, 2025
425e7ed
test: fix incorrect snapshots.
andycall Dec 24, 2025
0403d0a
fix(css): inherit CSSLength as computed value (preserve percentages)
andycall Dec 24, 2025
94b2f4d
fix(css): reset background clip/origin and relayout clip-text
andycall Dec 25, 2025
3517fd6
fix(webf/css): clamp negative padding to zero to avoid layout crash
andycall Dec 25, 2025
18a3ca0
fix(css): ignore negative font-size to prevent Flutter textScaler assert
andycall Dec 25, 2025
9f992a0
fix: fix all test specs.
andycall Dec 25, 2025
c818ef5
showcase: update showcases examples.
andycall Dec 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ jobs:
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.38.0'
flutter-version: '3.29.0'
channel: 'stable'

- name: Setup Git configuration
Expand Down
32,471 changes: 16,233 additions & 16,238 deletions bridge/core/bridge_polyfill.c

Large diffs are not rendered by default.

89 changes: 89 additions & 0 deletions bridge/core/css/blink_inline_style_validation_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2022-present The WebF authors. All rights reserved.
*/

#include "gtest/gtest.h"

#include <cstring>

#include "foundation/native_string.h"
#include "foundation/native_type.h"
#include "foundation/string/wtf_string.h"
#include "foundation/ui_command_buffer.h"
#include "webf_test_env.h"

using namespace webf;

namespace {

std::string CommandArg01ToUTF8(const UICommandItem& item) {
if (item.string_01 == 0 || item.args_01_length == 0) {
return "";
}
const auto* utf16 = reinterpret_cast<const UChar*>(static_cast<uintptr_t>(item.string_01));
return String(utf16, static_cast<size_t>(item.args_01_length)).ToUTF8String();
}

std::string SharedNativeStringToUTF8(const SharedNativeString* s) {
if (!s || !s->string() || s->length() == 0) {
return "";
}
return String(reinterpret_cast<const UChar*>(s->string()), static_cast<size_t>(s->length())).ToUTF8String();
}

bool HasSetStyleWithKeyValue(ExecutingContext* context, const std::string& key, const std::string& value) {
auto* pack = static_cast<UICommandBufferPack*>(context->uiCommandBuffer()->data());
auto* items = static_cast<UICommandItem*>(pack->data);
for (int64_t i = 0; i < pack->length; ++i) {
const UICommandItem& item = items[i];
if (item.type != static_cast<int32_t>(UICommand::kSetStyle)) {
continue;
}
if (CommandArg01ToUTF8(item) != key) {
continue;
}
auto* payload =
reinterpret_cast<NativeStyleValueWithHref*>(static_cast<uintptr_t>(item.nativePtr2));
if (!payload) {
continue;
}
if (SharedNativeStringToUTF8(payload->value) == value) {
return true;
}
}
return false;
}

} // namespace

TEST(BlinkCSSStyleDeclarationValidation, RejectsInvalidFontSize) {
bool static errorCalled = false;
webf::WebFPage::consoleMessageHandler = [](void*, const std::string&, int) {};

auto env = TEST_init([](double, const char* errmsg) {
WEBF_LOG(VERBOSE) << errmsg;
errorCalled = true;
}, nullptr, 0, /*enable_blink=*/1);

auto* context = env->page()->executingContext();

// Flush initial microtasks/style export and clear any bootstrap commands.
TEST_runLoop(context);
context->uiCommandBuffer()->clear();

// Set a valid value first.
const char* set_valid = "document.body.style.fontSize = '18px';";
env->page()->evaluateScript(set_valid, strlen(set_valid), "vm://", 0);
TEST_runLoop(context);
EXPECT_TRUE(HasSetStyleWithKeyValue(context, "fontSize", "18px"));

context->uiCommandBuffer()->clear();

// Invalid font-size should be rejected on the native (Blink) CSS side and
// thus should not be forwarded to Dart.
const char* set_invalid = "document.body.style.fontSize = '-1px';";
env->page()->evaluateScript(set_invalid, strlen(set_invalid), "vm://", 0);
TEST_runLoop(context);
EXPECT_FALSE(HasSetStyleWithKeyValue(context, "fontSize", "-1px"));
EXPECT_EQ(errorCalled, false);
}
60 changes: 45 additions & 15 deletions bridge/core/css/style_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1195,20 +1195,30 @@ void StyleEngine::RecalcStyleForSubtree(Element& root_element) {
}
for (unsigned i = 0; i < pseudo_set->PropertyCount(); ++i) {
auto prop = pseudo_set->PropertyAt(i);
CSSPropertyID id = prop.Id();
if (id == CSSPropertyID::kInvalid) {
continue;
}
const auto* value_ptr = prop.Value();
if (!value_ptr || !(*value_ptr)) {
continue;
}
AtomicString prop_name = prop.Name().ToAtomicString();
String value_string = pseudo_set->GetPropertyValueWithHint(prop_name, i);
if (value_string.IsNull()) value_string = String("");
String base_href_string = pseudo_set->GetPropertyBaseHrefWithHint(prop_name, i);
auto key_ns = prop_name.ToStylePropertyNameNativeString();
auto* payload =
reinterpret_cast<NativePseudoStyleWithHref*>(dart_malloc(sizeof(NativePseudoStyleWithHref)));
payload->key = key_ns.release();
payload->value = stringToNativeString(value_string).release();
if (!base_href_string.IsEmpty()) {
payload->href = stringToNativeString(base_href_string.ToUTF8String()).release();
} else {
payload->href = nullptr;
}
String value_string = pseudo_set->GetPropertyValueWithHint(prop_name, i);
if (value_string.IsNull()) {
value_string = (*value_ptr)->CssTextForSerialization();
}
String base_href_string = pseudo_set->GetPropertyBaseHrefWithHint(prop_name, i);
auto key_ns = prop_name.ToStylePropertyNameNativeString();
auto* payload =
reinterpret_cast<NativePseudoStyleWithHref*>(dart_malloc(sizeof(NativePseudoStyleWithHref)));
payload->key = key_ns.release();
payload->value = stringToNativeString(value_string).release();
if (!base_href_string.IsEmpty()) {
payload->href = stringToNativeString(base_href_string.ToUTF8String()).release();
} else {
payload->href = nullptr;
}
auto pseudo_atom = AtomicString::CreateFromUTF8(pseudo_name);
auto pseudo_ns = pseudo_atom.ToNativeString();
ctx->uiCommandBuffer()->AddCommand(UICommand::kSetPseudoStyle, std::move(pseudo_ns),
Expand Down Expand Up @@ -1356,9 +1366,19 @@ void StyleEngine::RecalcStyleForSubtree(Element& root_element) {
}
for (unsigned i = 0; i < pseudo_set->PropertyCount(); ++i) {
auto prop = pseudo_set->PropertyAt(i);
CSSPropertyID id = prop.Id();
if (id == CSSPropertyID::kInvalid) {
continue;
}
const auto* value_ptr = prop.Value();
if (!value_ptr || !(*value_ptr)) {
continue;
}
AtomicString prop_name = prop.Name().ToAtomicString();
String value_string = pseudo_set->GetPropertyValueWithHint(prop_name, i);
if (value_string.IsNull()) value_string = String("");
if (value_string.IsNull()) {
value_string = (*value_ptr)->CssTextForSerialization();
}
String base_href_string = pseudo_set->GetPropertyBaseHrefWithHint(prop_name, i);

auto key_ns = prop_name.ToStylePropertyNameNativeString();
Expand Down Expand Up @@ -1632,9 +1652,19 @@ void StyleEngine::RecalcStyleForElementOnly(Element& element) {
el->bindingObject(), nullptr);
for (unsigned i = 0; i < pseudo_set->PropertyCount(); ++i) {
auto prop = pseudo_set->PropertyAt(i);
CSSPropertyID id = prop.Id();
if (id == CSSPropertyID::kInvalid) {
continue;
}
const auto* value_ptr = prop.Value();
if (!value_ptr || !(*value_ptr)) {
continue;
}
AtomicString prop_name = prop.Name().ToAtomicString();
String value_string = pseudo_set->GetPropertyValueWithHint(prop_name, i);
if (value_string.IsNull()) value_string = String("");
if (value_string.IsNull()) {
value_string = (*value_ptr)->CssTextForSerialization();
}
String base_href_string = pseudo_set->GetPropertyBaseHrefWithHint(prop_name, i);

auto key_ns = prop_name.ToStylePropertyNameNativeString();
Expand Down
11 changes: 11 additions & 0 deletions bridge/core/dom/document.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
* Copyright (C) 2022-present The WebF authors. All rights reserved.
*/
#include "document.h"
#include <chrono>

#include "../../foundation/string/ascii_types.h"
#include "binding_call_methods.h"
#include "bindings/qjs/exception_message.h"
Expand All @@ -29,6 +31,7 @@
#include "element_traversal.h"
#include "event_factory.h"
#include "foundation/native_value_converter.h"
#include "foundation/logging.h"
#include "core/script_forbidden_scope.h"
#include "html_element_factory.h"
#include "svg_element_factory.h"
Expand Down Expand Up @@ -611,6 +614,8 @@ void Document::UpdateStyleForThisDocument() {
return;
}

auto start_time = std::chrono::steady_clock::now();

// Ensure we have a StyleEngine instance before driving the Blink-style
// style update sequence.
StyleEngine& style_engine = EnsureStyleEngine();
Expand All @@ -621,6 +626,12 @@ void Document::UpdateStyleForThisDocument() {
style_engine.InvalidateEnvDependentStylesIfNeeded();
UpdateStyleInvalidationIfNeeded();
UpdateStyle();

auto duration_ms =
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_time).count();
if (duration_ms != 0) {
WEBF_LOG(VERBOSE) << "[Style] Document::UpdateStyleForThisDocument elapsed: " << duration_ms << "ms" << std::endl;
}
}

void Document::EvaluateMediaQueryListIfNeeded() {
Expand Down
19 changes: 18 additions & 1 deletion bridge/core/dom/element.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1042,8 +1042,21 @@ void Element::SetInlineStyleFromString(const webf::AtomicString& new_style_strin
GetExecutingContext()->uiCommandBuffer()->AddCommand(UICommand::kClearStyle, nullptr, bindingObject(), nullptr);
for (unsigned i = 0; i < count; ++i) {
auto property = inline_style->PropertyAt(i);
CSSPropertyID id = property.Id();
if (id == CSSPropertyID::kInvalid) {
continue;
}
const auto* value_ptr = property.Value();
if (!value_ptr || !(*value_ptr)) {
// Skip parse-error or missing values; they should not be forwarded to Dart.
continue;
}
AtomicString prop_name = property.Name().ToAtomicString();
String value_string = inline_style->GetPropertyValueWithHint(prop_name, i);
if (value_string.IsNull()) {
value_string = (*value_ptr)->CssTextForSerialization();
}
String base_href_string = inline_style->GetPropertyBaseHrefWithHint(prop_name, i);

// Normalize CSS property names (e.g. background-color, text-align) to the
// camelCase form expected by the Dart style engine before sending them
Expand All @@ -1052,7 +1065,11 @@ void Element::SetInlineStyleFromString(const webf::AtomicString& new_style_strin
std::unique_ptr<SharedNativeString> args_01 = prop_name.ToStylePropertyNameNativeString();
auto* payload = reinterpret_cast<NativeStyleValueWithHref*>(dart_malloc(sizeof(NativeStyleValueWithHref)));
payload->value = stringToNativeString(value_string).release();
payload->href = nullptr;
if (!base_href_string.IsEmpty()) {
payload->href = stringToNativeString(base_href_string.ToUTF8String()).release();
} else {
payload->href = nullptr;
}
GetExecutingContext()->uiCommandBuffer()->AddCommand(UICommand::kSetStyle, std::move(args_01), bindingObject(),
payload);
}
Expand Down
6 changes: 3 additions & 3 deletions bridge/polyfill/src/hybrid-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export interface HybridHistoryInterface {
* @param result Optional result to pass back to the previous screen
* @returns True if the route was popped, false otherwise
*/
maybePop(result?: any): boolean;
maybePop(result?: any): Promise<boolean>;

/**
* Pop the current route and push a new named route
Expand Down Expand Up @@ -269,8 +269,8 @@ class HybridHistory implements HybridHistoryInterface {
* @param result Optional result to pass back to the previous screen
* @returns True if the route was popped, false otherwise
*/
maybePop(result?: any): boolean {
return webf.invokeModule('HybridHistory', 'maybePop', result !== undefined ? result : null) === 'true';
async maybePop(result?: any): Promise<boolean> {
return (await webf.invokeModuleAsync('HybridHistory', 'maybePop', result !== undefined ? result : null)) === 'true';
}

/**
Expand Down
Loading
Loading