Skip to content

Commit c526820

Browse files
committed
feat: support watch inline style changes.
1 parent 8ea96ad commit c526820

File tree

8 files changed

+92
-2
lines changed

8 files changed

+92
-2
lines changed

bridge/bindings/qjs/microtask_queue.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,8 @@ void MicrotaskQueue::EnqueueMicrotask(webf::MicrotaskCallback callback, void* da
2424
queue_.emplace_back(std::move(queue_item));
2525
}
2626

27+
bool MicrotaskQueue::empty() {
28+
return queue_.size() == 0;
29+
}
30+
2731
}

bridge/bindings/qjs/microtask_queue.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class MicrotaskQueue final {
2222

2323
void DrainMicrotaskQueue();
2424
void EnqueueMicrotask(MicrotaskCallback callback, void* data = nullptr);
25+
bool empty();
2526

2627
private:
2728

bridge/core/css/inline_css_style_declaration.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#include "core/executing_context.h"
99
#include "core/html/parser/html_parser.h"
1010
#include "css_property_list.h"
11+
#include "core/dom/mutation_observer_interest_group.h"
12+
#include "html_names.h"
13+
#include "element_namespace_uris.h"
1114

1215
namespace webf {
1316

@@ -153,6 +156,8 @@ void InlineCssStyleDeclaration::setCssText(const std::string& css_text, webf::Ex
153156
InternalSetProperty(css_key, AtomicString(ctx(), css_value));
154157
}
155158
}
159+
160+
InlineStyleChanged();
156161
}
157162

158163
void InlineCssStyleDeclaration::Trace(GCVisitor* visitor) const {
@@ -173,6 +178,18 @@ std::string InlineCssStyleDeclaration::ToString() const {
173178
return s;
174179
}
175180

181+
void InlineCssStyleDeclaration::InlineStyleChanged() {
182+
assert(owner_element_->IsStyledElement());
183+
184+
if (std::shared_ptr<MutationObserverInterestGroup> recipients =
185+
MutationObserverInterestGroup::CreateForAttributesMutation(
186+
*owner_element_, html_names::kStyleAttr)) {
187+
AtomicString old_value;
188+
recipients->EnqueueMutationRecord(MutationRecord::CreateAttributes(
189+
owner_element_, html_names::kStyleAttr, element_namespace_uris::khtml, old_value));
190+
}
191+
}
192+
176193
bool InlineCssStyleDeclaration::NamedPropertyQuery(const AtomicString& key, ExceptionState&) {
177194
return cssPropertyList.count(key.ToStdString(ctx())) > 0;
178195
}
@@ -199,8 +216,12 @@ bool InlineCssStyleDeclaration::InternalSetProperty(std::string& name, const Ato
199216
return true;
200217
}
201218

219+
AtomicString old_value = properties_[name];
220+
202221
properties_[name] = value;
203222

223+
InlineStyleChanged();
224+
204225
std::unique_ptr<SharedNativeString> args_01 = stringToNativeString(name);
205226
GetExecutingContext()->uiCommandBuffer()->addCommand(
206227
UICommand::kSetStyle, std::move(args_01), owner_element_->bindingObject(), value.ToNativeString(ctx()).release());
@@ -218,6 +239,8 @@ AtomicString InlineCssStyleDeclaration::InternalRemoveProperty(std::string& name
218239
AtomicString return_value = properties_[name];
219240
properties_.erase(name);
220241

242+
InlineStyleChanged();
243+
221244
std::unique_ptr<SharedNativeString> args_01 = stringToNativeString(name);
222245
GetExecutingContext()->uiCommandBuffer()->addCommand(UICommand::kSetStyle, std::move(args_01),
223246
owner_element_->bindingObject(), nullptr);

bridge/core/css/inline_css_style_declaration.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class InlineCssStyleDeclaration : public CSSStyleDeclaration {
3636

3737
[[nodiscard]] std::string ToString() const;
3838

39+
void InlineStyleChanged();
40+
3941
bool NamedPropertyQuery(const AtomicString&, ExceptionState&) override;
4042
void NamedPropertyEnumerator(std::vector<AtomicString>& names, ExceptionState&) override;
4143

bridge/core/dom/mutation_observer.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class MutationObserverAgent {
6464

6565
private:
6666
void DeliverMutations() {
67+
MemberMutationScope scopes{context_};
6768
// These steps are defined in DOM Standard's "notify mutation observers".
6869
// https://dom.spec.whatwg.org/#notify-mutation-observers
6970
MutationObserverVector observers(active_mutation_observers_.begin(), active_mutation_observers_.end());
@@ -144,10 +145,10 @@ void MutationObserver::observe(Node* node, const std::shared_ptr<MutationObserve
144145
observer_init->hasCharacterDataOldValue()))
145146
options |= kMutationTypeCharacterData;
146147

147-
if (observer_init->childList())
148+
if (observer_init->hasChildList() && observer_init->childList())
148149
options |= kMutationTypeChildList;
149150

150-
if (observer_init->subtree())
151+
if (observer_init->hasSubtree() && observer_init->subtree())
151152
options |= kSubtree;
152153

153154
if (!(options & kMutationTypeAttributes)) {

bridge/core/dom/node_test.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,55 @@ TEST(Node, appendChild) {
2828
EXPECT_EQ(logCalled, true);
2929
}
3030

31+
TEST(Node, MutationObserver) {
32+
bool static errorCalled = false;
33+
bool static logCalled = false;
34+
webf::WebFPage::consoleMessageHandler = [](void* ctx, const std::string& message, int logLevel) {
35+
logCalled = true;
36+
};
37+
auto env = TEST_init([](int32_t contextId, const char* errmsg) { errorCalled = true; });
38+
auto context = env->page()->GetExecutingContext();
39+
const char* code = R"(
40+
const container = document.createElement('div');
41+
document.body.appendChild(container);
42+
43+
// Callback function to execute when mutations are observed
44+
const callback = function (mutationList, observer) {
45+
console.log('c');
46+
};
47+
48+
// Create an observer instance linked to the callback function
49+
const observer = new MutationObserver(callback);
50+
51+
// Options for the observer (which mutations to observe)
52+
const config = { attributes: true, childList: true, subtree: true, attributeOldValue: true };
53+
54+
// Start observing the target node for configured mutations
55+
observer.observe(container, config);
56+
57+
container.appendChild(document.createTextNode('TEXT'));
58+
59+
Promise.resolve().then(() => {
60+
console.log('1234');
61+
container.appendChild(document.createTextNode('TEXT'));
62+
Promise.resolve().then(() => {
63+
console.log('444');
64+
container.removeChild(container.firstChild);
65+
Promise.resolve().then(() => {
66+
console.log('555');
67+
});
68+
});
69+
});
70+
)";
71+
env->page()->evaluateScript(code, strlen(code), "vm://", 0);
72+
73+
TEST_runLoop(context);
74+
75+
EXPECT_EQ(errorCalled, false);
76+
EXPECT_EQ(logCalled, true);
77+
}
78+
79+
3180
TEST(Node, nodeName) {
3281
bool static errorCalled = false;
3382
bool static logCalled = false;

bridge/core/executing_context.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,11 @@ void ExecutingContext::ReportError(JSValueConst error) {
267267
}
268268

269269
void ExecutingContext::DrainMicrotasks() {
270+
if (is_draining_microtasks_) return;
271+
is_draining_microtasks_ = true;
270272
microtask_queue_->DrainMicrotaskQueue();
271273
DrainPendingPromiseJobs();
274+
is_draining_microtasks_ = false;
272275
}
273276

274277
void ExecutingContext::EnqueueMicrotask(MicrotaskCallback callback, void* data) {
@@ -280,6 +283,12 @@ void ExecutingContext::DrainPendingPromiseJobs() {
280283
JSContext* pctx;
281284
int finished = JS_ExecutePendingJob(script_state_.runtime(), &pctx);
282285
while (finished != 0) {
286+
bool is_microtask_empty = microtask_queue_->empty();
287+
288+
if (!is_microtask_empty) {
289+
microtask_queue_->DrainMicrotaskQueue();
290+
}
291+
283292
finished = JS_ExecutePendingJob(script_state_.runtime(), &pctx);
284293
if (finished == -1) {
285294
break;

bridge/core/executing_context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ class ExecutingContext {
197197
MemberMutationScope* active_mutation_scope{nullptr};
198198
std::set<ScriptWrappable*> active_wrappers_;
199199
std::unique_ptr<MicrotaskQueue> microtask_queue_ = std::make_unique<MicrotaskQueue>();
200+
bool is_draining_microtasks_ = false;
200201
};
201202

202203
class ObjectProperty {

0 commit comments

Comments
 (0)