-
-
Notifications
You must be signed in to change notification settings - Fork 24
Implement GlyphItemIter manually #161
base: master
Are you sure you want to change the base?
Changes from all commits
3a70ef0
21ca84e
73f8bf2
aff3ba2
d1cb61c
b2fb7d6
8cbf41c
c2cfba3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
// Copyright 2019, The Gtk-rs Project Developers. | ||
// See the COPYRIGHT file at the top-level directory of this distribution. | ||
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT> | ||
|
||
use glib::translate::*; | ||
use pango_sys; | ||
use std::marker::PhantomData; | ||
use GlyphItem; | ||
|
||
//Note: This type not exported | ||
glib_wrapper! { | ||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
pub struct GlyphItemIter(Boxed<pango_sys::PangoGlyphItemIter>); | ||
|
||
match fn { | ||
copy => |ptr| pango_sys::pango_glyph_item_iter_copy(mut_override(ptr)), | ||
free => |ptr| pango_sys::pango_glyph_item_iter_free(ptr), | ||
init => |_ptr| (), | ||
clear => |_ptr| (), | ||
get_type => || pango_sys::pango_glyph_item_iter_get_type(), | ||
} | ||
} | ||
|
||
impl GlyphItemIter { | ||
pub(crate) unsafe fn init_end(glyph_item: &GlyphItem, text: &str) -> Option<GlyphItemIter> { | ||
let mut iter = GlyphItemIter::uninitialized(); | ||
let ret = from_glib(pango_sys::pango_glyph_item_iter_init_end( | ||
iter.to_glib_none_mut().0, | ||
mut_override(glyph_item.to_glib_none().0), | ||
text.to_glib_none().0, | ||
)); | ||
if ret { | ||
Some(iter) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
pub(crate) unsafe fn init_start(glyph_item: &GlyphItem, text: &str) -> Option<GlyphItemIter> { | ||
let mut iter = GlyphItemIter::uninitialized(); | ||
let ret = from_glib(pango_sys::pango_glyph_item_iter_init_start( | ||
iter.to_glib_none_mut().0, | ||
mut_override(glyph_item.to_glib_none().0), | ||
text.to_glib_none().0, | ||
)); | ||
if ret { | ||
Some(iter) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
pub fn next_cluster(&mut self) -> bool { | ||
unsafe { | ||
from_glib(pango_sys::pango_glyph_item_iter_next_cluster( | ||
self.to_glib_none_mut().0, | ||
)) | ||
} | ||
} | ||
|
||
pub fn prev_cluster(&mut self) -> bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe there should also be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMHO this need be other type instead of this, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? This literally is an iterator :) A lifetime parameter is also needed on this type There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because reverse variant (from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also first call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, so might indeed need an adapter struct :) Weird API! |
||
unsafe { | ||
from_glib(pango_sys::pango_glyph_item_iter_prev_cluster( | ||
self.to_glib_none_mut().0, | ||
)) | ||
} | ||
} | ||
|
||
pub fn to_data(&self) -> GlyphItemIteratorData { | ||
GlyphItemIteratorData { | ||
start_glyph: self.0.start_glyph as usize, | ||
end_glyph: self.0.end_glyph as usize, | ||
start_index: self.0.start_index as usize, | ||
end_index: self.0.end_index as usize, | ||
start_char: self.0.start_char as usize, | ||
end_char: self.0.end_char as usize, | ||
} | ||
} | ||
} | ||
|
||
pub struct GlyphItemIteratorData { | ||
pub start_glyph: usize, | ||
pub start_index: usize, | ||
pub start_char: usize, | ||
|
||
pub end_glyph: usize, | ||
pub end_index: usize, | ||
pub end_char: usize, | ||
} | ||
|
||
enum NormalIterator {} | ||
enum ReverseIterator {} | ||
|
||
struct GlyphItemIterator<'a, T> { | ||
item: &'a GlyphItem, | ||
text: &'a str, | ||
iter: Option<GlyphItemIter>, | ||
_mode: PhantomData<T>, | ||
} | ||
|
||
impl GlyphItem { | ||
pub fn iter<'a>( | ||
&'a self, | ||
text: &'a str, | ||
) -> impl DoubleEndedIterator<Item = GlyphItemIteratorData> + 'a { | ||
GlyphItemIterator::<NormalIterator> { | ||
item: self, | ||
text, | ||
iter: None, | ||
_mode: PhantomData, | ||
} | ||
} | ||
|
||
pub fn reverse_iter<'a>( | ||
&'a self, | ||
text: &'a str, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do we ensure that the text corresponds to the glyph item? From reading the code it seems like we otherwise would get invalid memory accesses (if the text is smaller than the glyph) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know way to ensure :( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can get PangoItem.length and compare with text length and chars count, but it not give us 100% There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know either, needs someone to dig into this API There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @EPashkin This one is the remaining issue? I guess this needs some talking to Pango developers to figure out what to do about this here :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMHO yes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any news on this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @GuillaumeGomez Sorry, but I still have no idea how do this safe, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
) -> impl DoubleEndedIterator<Item = GlyphItemIteratorData> + 'a { | ||
GlyphItemIterator::<ReverseIterator> { | ||
item: self, | ||
text, | ||
iter: None, | ||
_mode: PhantomData, | ||
} | ||
} | ||
} | ||
|
||
impl<'a> Iterator for GlyphItemIterator<'a, NormalIterator> { | ||
type Item = GlyphItemIteratorData; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
if let Some(ref mut iter) = self.iter { | ||
if iter.next_cluster() { | ||
Some(iter.to_data()) | ||
} else { | ||
None | ||
} | ||
} else { | ||
let iter = unsafe { GlyphItemIter::init_start(self.item, self.text) }; | ||
if let Some(iter) = iter { | ||
let data = iter.to_data(); | ||
self.iter = Some(iter); | ||
Some(data) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl<'a> Iterator for GlyphItemIterator<'a, ReverseIterator> { | ||
type Item = GlyphItemIteratorData; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
if let Some(ref mut iter) = self.iter { | ||
if iter.prev_cluster() { | ||
Some(iter.to_data()) | ||
} else { | ||
None | ||
} | ||
} else { | ||
let iter = unsafe { GlyphItemIter::init_end(self.item, self.text) }; | ||
if let Some(iter) = iter { | ||
let data = iter.to_data(); | ||
self.iter = Some(iter); | ||
Some(data) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl<'a> DoubleEndedIterator for GlyphItemIterator<'a, NormalIterator> { | ||
fn next_back(&mut self) -> Option<Self::Item> { | ||
if let Some(ref mut iter) = self.iter { | ||
if iter.prev_cluster() { | ||
Some(iter.to_data()) | ||
} else { | ||
None | ||
} | ||
} else if let Some(iter) = unsafe { GlyphItemIter::init_end(self.item, self.text) } { | ||
let data = iter.to_data(); | ||
self.iter = Some(iter); | ||
Some(data) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
impl<'a> DoubleEndedIterator for GlyphItemIterator<'a, ReverseIterator> { | ||
fn next_back(&mut self) -> Option<Self::Item> { | ||
if let Some(ref mut iter) = self.iter { | ||
if iter.next_cluster() { | ||
Some(iter.to_data()) | ||
} else { | ||
None | ||
} | ||
} else if let Some(iter) = unsafe { GlyphItemIter::init_start(self.item, self.text) } { | ||
let data = iter.to_data(); | ||
self.iter = Some(iter); | ||
Some(data) | ||
} else { | ||
None | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a lifetime parameter. The the glyph item used for initialization must stay alive at least as long as the iterator. The iterator "borrows" the item.