Fixed `FallbackConfig`.

This commit is contained in:
Samuel Guerra 2023-05-31 18:48:42 -03:00
parent 2101834526
commit b8ce11cfca
2 changed files with 57 additions and 178 deletions

View File

@ -1,8 +1,3 @@
* Test emoji, looks like webrender supports then.
- We need more than one "fallback" font?
- Right now we use "Segoe UI Symbol" in Windows.
- We need to fallback to "Segoe UI Emoji" instead, or have both?
# TextInput
* Implement cursor position.
@ -29,17 +24,26 @@
- Input replaces selection.
- Char input, paste, IME
- Impl cut & copy.
* Implement custom node access to text.
- Clone text var in `ResolvedText`?
- Getter property `get_transformed_text`, to get the text after whitespace transforms?
* Implement IME.
- See https://github.com/rust-windowing/winit/issues/1497
# Clipboard
* Implement image copy&paste in image example.
# Config
# Emoji Rendering
* `FallbackConfig` always inserts a copy on the write config, should stay bound to fallback.
- We want the "config/fallback" to be used like the "workspace/user" settings of VSCode.
- When the fallback changes and it is not overridden the config var should update.
- When it is set, the config file only should update.
- Like a `CowVar`.
- But we still have the embedded ultimate fallback.
* Tech is called CPAL/COLR.
- Layered glyphs of different colors.
* Looks like webrender expects the glyphs to be pre-processed?
* Newer versions of harfbuzz have function to get the colors.
* We need more than one "fallback" font?
- Right now we use "Segoe UI Symbol" in Windows.
- We need to fallback to "Segoe UI Emoji" instead, or have both?
- See what browsers do, maybe we need a "front" font, that is added on top of other fonts?

View File

@ -25,103 +25,40 @@ impl<S: Config, F: Config> AnyConfig for FallbackConfig<S, F> {
}
fn get_raw(&mut self, key: ConfigKey, default: RawConfigValue, shared: bool) -> BoxedVar<RawConfigValue> {
let over = self.config.get_raw(key.clone(), default.clone(), shared);
let cfg_var = self.config.get_raw(key.clone(), default.clone(), shared);
if self.config.contains_key(&key) {
return over;
// no need for fallback
return cfg_var;
}
let fallback = self.fallback.get_raw(key, default, shared);
let result = var(fallback.get());
let fall_var = self.fallback.get_raw(key, default, shared);
#[derive(Clone, Copy)]
enum State {
Fallback,
FallbackUpdated,
Over,
OverUpdated,
}
let state = Arc::new(atomic::Atomic::new(State::Fallback));
let res_var = var(fall_var.get());
// hook fallback, signal `result` that an update is flowing from the fallback.
let wk_result = result.downgrade();
fallback
.hook(Box::new(clmv!(state, |value| {
match state.load(atomic::Ordering::Relaxed) {
State::Over | State::OverUpdated => {
// result -> over
return false;
}
_ => {}
}
let fall_to_res = fall_var.bind(&res_var);
// fallback -> result
if let Some(result) = wk_result.upgrade() {
state.store(State::FallbackUpdated, atomic::Ordering::Relaxed);
result.set(value.as_any().downcast_ref::<RawConfigValue>().unwrap().clone());
true
} else {
// weak-ref to avoid circular ref.
false
}
})))
.perm();
// hook over, signals `result` that an update is flowing from the override.
let wk_result = result.downgrade();
over.hook(Box::new(clmv!(state, |value| {
match state.load(atomic::Ordering::Relaxed) {
State::OverUpdated => {
// result -> over
state.store(State::Over, atomic::Ordering::Relaxed);
}
_ => {
// over -> result
let value = value.as_any().downcast_ref::<RawConfigValue>().unwrap();
state.store(State::OverUpdated, atomic::Ordering::Relaxed);
if let Some(result) = wk_result.upgrade() {
result.set(value.clone());
let fall_var = Mutex::new(Some((fall_var, fall_to_res)));
res_var
.hook(Box::new(move |v| {
let mut fall_var = fall_var.lock();
if let Some((fv, _)) = &*fall_var {
if fv.last_update() != VARS.update_id() {
// update from assign, disconnect from fallback.
*fall_var = None;
let _ = cfg_var.set(v.as_any().downcast_ref::<RawConfigValue>().unwrap().clone());
} else {
// weak-ref to avoid circular ref.
return false;
// update from fallback
return true;
}
} else {
let _ = cfg_var.set_ne(v.as_any().downcast_ref::<RawConfigValue>().unwrap().clone());
}
}
true
})))
.perm();
// hook result, on first callback not caused by `fallback` drops it and changes to `over`.
let fallback = Mutex::new(Some(fallback));
result
.hook(Box::new(move |value| {
match state.load(atomic::Ordering::Relaxed) {
State::Fallback => {
// result -> over(first)
state.store(State::Over, atomic::Ordering::Relaxed);
*fallback.lock() = None;
let value = value.as_any().downcast_ref::<RawConfigValue>().unwrap().clone();
let _ = over.set_ne(value);
}
State::FallbackUpdated => {
// fallback -> result
state.store(State::Fallback, atomic::Ordering::Relaxed);
}
State::Over => {
// result -> over
let value = value.as_any().downcast_ref::<RawConfigValue>().unwrap().clone();
let _ = over.set_ne(value);
}
State::OverUpdated => {
// over -> result
state.store(State::Over, atomic::Ordering::Relaxed);
}
}
true
}))
.perm();
result.boxed()
res_var.boxed()
}
fn contains_key(&self, key: &ConfigKey) -> bool {
@ -132,100 +69,38 @@ impl<S: Config, F: Config> Config for FallbackConfig<S, F> {
fn get<T: ConfigValue>(&mut self, key: impl Into<ConfigKey>, default: impl FnOnce() -> T) -> BoxedVar<T> {
let key = key.into();
let default = default();
let fallback = self.fallback.get(key.clone(), || default.clone());
let over = var(None::<T>); // TODO, actually provided by self.source
if over.with(|s| s.is_some()) {
return self.config.get(key, move || default);
let cfg_var = self.config.get(key.clone(), || default.clone());
if self.config.contains_key(&key) {
// no need for fallback
return cfg_var;
}
let result = var(fallback.get());
#[derive(Clone, Copy)]
enum State {
Fallback,
FallbackUpdated,
Over,
OverUpdated,
}
let state = Arc::new(atomic::Atomic::new(State::Fallback));
let fall_var = self.fallback.get(key, || default);
// hook fallback, signal `result` that an update is flowing from the fallback.
let wk_result = result.downgrade();
fallback
.hook(Box::new(clmv!(state, |value| {
match state.load(atomic::Ordering::Relaxed) {
State::Over | State::OverUpdated => {
// result -> over
return false;
}
_ => {}
}
let res_var = var(fall_var.get());
// fallback -> result
if let Some(result) = wk_result.upgrade() {
state.store(State::FallbackUpdated, atomic::Ordering::Relaxed);
result.set(value.as_any().downcast_ref::<T>().unwrap().clone());
true
} else {
// weak-ref to avoid circular ref.
false
}
})))
.perm();
let fall_to_res = fall_var.bind(&res_var);
// hook over, signals `result` that an update is flowing from the override.
let wk_result = result.downgrade();
over.hook(Box::new(clmv!(state, |value| {
match state.load(atomic::Ordering::Relaxed) {
State::OverUpdated => {
// result -> over
state.store(State::Over, atomic::Ordering::Relaxed);
}
_ => {
// over -> result
if let Some(value) = value.as_any().downcast_ref::<Option<T>>().unwrap() {
state.store(State::OverUpdated, atomic::Ordering::Relaxed);
if let Some(result) = wk_result.upgrade() {
result.set(value.clone());
} else {
// weak-ref to avoid circular ref.
return false;
}
let fall_var = Mutex::new(Some((fall_var, fall_to_res)));
res_var
.hook(Box::new(move |v| {
let mut fall_var = fall_var.lock();
if let Some((fv, _)) = &*fall_var {
if fv.last_update() != VARS.update_id() {
// update from assign, disconnect from fallback.
*fall_var = None;
} else {
// update from fallback
return true;
}
}
}
true
})))
.perm();
// hook result, on first callback not caused by `fallback` drops it and changes to `over`.
let fallback = Mutex::new(Some(fallback));
result
.hook(Box::new(move |value| {
match state.load(atomic::Ordering::Relaxed) {
State::Fallback => {
// result -> over(first)
state.store(State::Over, atomic::Ordering::Relaxed);
*fallback.lock() = None;
over.set(Some(value.as_any().downcast_ref::<T>().unwrap().clone()));
}
State::FallbackUpdated => {
// fallback -> result
state.store(State::Fallback, atomic::Ordering::Relaxed);
}
State::Over => {
// result -> over
over.set(Some(value.as_any().downcast_ref::<T>().unwrap().clone()));
}
State::OverUpdated => {
// over -> result
state.store(State::Over, atomic::Ordering::Relaxed);
}
}
let _ = cfg_var.set(v.as_any().downcast_ref::<T>().unwrap().clone());
true
}))
.perm();
result.boxed()
res_var.boxed()
}
}