diff --git a/include/nana/paint/graphics.hpp b/include/nana/paint/graphics.hpp index bea13f4b..c0a8f56d 100644 --- a/include/nana/paint/graphics.hpp +++ b/include/nana/paint/graphics.hpp @@ -1,7 +1,7 @@ /* * Paint Graphics Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -116,6 +116,12 @@ namespace nana #ifdef _nana_std_has_string_view ::nana::size text_extent_size(std::string_view text) const; ::nana::size text_extent_size(std::wstring_view text) const; + + ///Only supports the wide string, because it is very hard to specify the begin and end position in a UTF-8 string. + ::nana::size glyph_extent_size(std::wstring_view text, std::size_t begin, std::size_t end) const; + + bool glyph_pixels(std::wstring_view text, unsigned* pxbuf) const; + std::unique_ptr glyph_pixels(std::wstring_view text) const; #else ::nana::size text_extent_size(const ::std::string&) const; ::nana::size text_extent_size(const char*, std::size_t len) const; @@ -124,11 +130,12 @@ namespace nana ::nana::size text_extent_size(const ::std::wstring&) const; ///< Computes the width and height of the specified string of text. ::nana::size text_extent_size(const wchar_t*, std::size_t length) const; ///< Computes the width and height of the specified string of text with the specified length. ::nana::size text_extent_size(const ::std::wstring&, std::size_t length) const; ///< Computes the width and height of the specified string of text with the specified length. -#endif ::nana::size glyph_extent_size(const wchar_t*, std::size_t length, std::size_t begin, std::size_t end) const; ::nana::size glyph_extent_size(const ::std::wstring&, std::size_t length, std::size_t begin, std::size_t end) const; + bool glyph_pixels(const wchar_t *, std::size_t length, unsigned* pxbuf) const; +#endif ::nana::size bidi_extent_size(const std::wstring&) const; ::nana::size bidi_extent_size(const std::string&) const; diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 9dc06848..d68b2159 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -834,8 +834,12 @@ namespace nana{ namespace widgets if (str_w > pixels) //Indicates the splitting of ts string { std::size_t len = ts.end - ts.begin; +#ifdef _nana_std_has_string_view + auto pxbuf = editor_.graph_.glyph_pixels({ts.begin, len}); +#else std::unique_ptr pxbuf(new unsigned[len]); editor_.graph_.glyph_pixels(ts.begin, len, pxbuf.get()); +#endif auto pxptr = pxbuf.get(); auto pxend = pxptr + len; @@ -3310,8 +3314,12 @@ namespace nana{ namespace widgets if (parser.entities().empty()) return; +#ifdef _nana_std_has_string_view + auto glyph_px = graph_.glyph_pixels({ str, len }); +#else std::unique_ptr glyph_px(new unsigned[len]); graph_.glyph_pixels(str, len, glyph_px.get()); +#endif auto glyphs = glyph_px.get(); auto px_h = line_height(); @@ -3561,8 +3569,12 @@ namespace nana{ namespace widgets unsigned select_pos = static_cast(ent_sbegin != ent.begin ? ent_sbegin - ent.begin : 0); unsigned select_len = static_cast(ent_send - ent_sbegin); +#ifdef _nana_std_has_string_view + auto pxbuf = graph_.glyph_pixels({ ent.begin, static_cast(len) }); +#else std::unique_ptr pxbuf{ new unsigned[len] }; graph_.glyph_pixels(ent.begin, len, pxbuf.get()); +#endif auto head_px = std::accumulate(pxbuf.get(), pxbuf.get() + select_pos, unsigned{}); auto select_px = std::accumulate(pxbuf.get() + select_pos, pxbuf.get() + select_pos + select_len, unsigned{}); @@ -3636,7 +3648,11 @@ namespace nana{ namespace widgets auto len = static_cast(ent.end - ent.begin); std::unique_ptr pxbuf(new unsigned[len]); +#ifdef _nana_std_has_string_view + if (graph_.glyph_pixels({ent.begin, len}, pxbuf.get())) +#else if (graph_.glyph_pixels(ent.begin, len, pxbuf.get())) +#endif { const auto px_end = pxbuf.get() + len; @@ -3695,7 +3711,11 @@ namespace nana{ namespace widgets //Characters of some bidi languages may transform in a word. //RTL std::unique_ptr pxbuf(new unsigned[len]); +#ifdef _nana_std_has_string_view + graph_.glyph_pixels({ent.begin, len}, pxbuf.get()); +#else graph_.glyph_pixels(ent.begin, len, pxbuf.get()); +#endif return std::accumulate(pxbuf.get() + (target - ent.begin), pxbuf.get() + len, text_w); } //LTR diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 46b685d1..14a76b0e 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -465,8 +465,116 @@ namespace paint { return detail::text_extent_size(impl_->handle, text.data(), text.length()); } - + nana::size graphics::glyph_extent_size(std::wstring_view text, std::size_t begin, std::size_t end) const + { + end = std::clamp(end, static_cast(0), static_cast(text.size())); + + if (nullptr == impl_->handle || text.empty() || begin >= end) return{}; + + nana::size sz; +#if defined(NANA_WINDOWS) + int * dx = new int[text.size()]; + + SIZE extents; + ::GetTextExtentExPoint(impl_->handle->context, text.data(), static_cast(text.size()), 0, 0, dx, &extents); + sz.width = dx[end - 1] - (begin ? dx[begin - 1] : 0); + unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels; + const wchar_t * pend = text.data() + end; + for (const wchar_t * p = text.data() + begin; p != pend; ++p) + { + if (*p == '\t') + sz.width += tab_pixels; + } + sz.height = extents.cy; + delete[] dx; +#elif defined(NANA_X11) + sz = text_extent_size(text.substr(begin, end - begin)); +#endif + return sz; + } + + bool graphics::glyph_pixels(std::wstring_view text, unsigned* pxbuf) const + { + if (nullptr == impl_->handle || nullptr == impl_->handle->context || nullptr == pxbuf) return false; + + if (text.empty()) return true; + + unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels; +#if defined(NANA_WINDOWS) + int * dx = new int[text.size()]; + SIZE extents; + ::GetTextExtentExPoint(impl_->handle->context, text.data(), static_cast(text.size()), 0, 0, dx, &extents); + + pxbuf[0] = (text[0] == '\t' ? tab_pixels : dx[0]); + + for (std::size_t i = 1; i < text.size(); ++i) + { + pxbuf[i] = (text[i] == '\t' ? tab_pixels : dx[i] - dx[i - 1]); + } + delete[] dx; +#elif defined(NANA_X11) && defined(NANA_USE_XFT) + + auto disp = nana::detail::platform_spec::instance().open_display(); + auto xft = reinterpret_cast(impl_->handle->font->native_handle()); + + XGlyphInfo extents; + for (std::size_t i = 0; i < len; ++i) + { + if (text[i] != '\t') + { + FT_UInt glyphs = ::XftCharIndex(disp, xft, text[i]); + ::XftGlyphExtents(disp, xft, &glyphs, 1, &extents); + pxbuf[i] = extents.xOff; + } + else + pxbuf[i] = tab_pixels; + } +#endif + return true; + } + + std::unique_ptr graphics::glyph_pixels(std::wstring_view text) const + { + if (nullptr == impl_->handle || nullptr == impl_->handle->context) return {}; + + if (text.empty()) return std::unique_ptr{new unsigned[1]}; + + unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels; +#if defined(NANA_WINDOWS) + int * dx = new int[text.size()]; + SIZE extents; + ::GetTextExtentExPoint(impl_->handle->context, text.data(), static_cast(text.size()), 0, 0, dx, &extents); + + auto pxbuf = std::unique_ptr{ new unsigned[text.size()] }; + + pxbuf[0] = (text[0] == '\t' ? tab_pixels : dx[0]); + + for (std::size_t i = 1; i < text.size(); ++i) + { + pxbuf[i] = (text[i] == '\t' ? tab_pixels : dx[i] - dx[i - 1]); + } + delete[] dx; +#elif defined(NANA_X11) && defined(NANA_USE_XFT) + + auto disp = nana::detail::platform_spec::instance().open_display(); + auto xft = reinterpret_cast(impl_->handle->font->native_handle()); + + XGlyphInfo extents; + for (std::size_t i = 0; i < len; ++i) + { + if (text[i] != '\t') + { + FT_UInt glyphs = ::XftCharIndex(disp, xft, text[i]); + ::XftGlyphExtents(disp, xft, &glyphs, 1, &extents); + pxbuf[i] = extents.xOff; + } + else + pxbuf[i] = tab_pixels; + } +#endif + return pxbuf; + } #else ::nana::size graphics::text_extent_size(const ::std::string& text) const { @@ -498,11 +606,10 @@ namespace paint { return detail::text_extent_size(impl_->handle, str.c_str(), len); } -#endif nana::size graphics::glyph_extent_size(const wchar_t * str, std::size_t len, std::size_t begin, std::size_t end) const { - if(len < end) end = len; + if (len < end) end = len; if (nullptr == impl_->handle || nullptr == str || 0 == len || begin >= end) return{}; nana::size sz; @@ -513,13 +620,13 @@ namespace paint sz.width = dx[end - 1] - (begin ? dx[begin - 1] : 0); unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels; const wchar_t * pend = str + end; - for(const wchar_t * p = str + begin; p != pend; ++p) + for (const wchar_t * p = str + begin; p != pend; ++p) { - if(*p == '\t') + if (*p == '\t') sz.width += tab_pixels; } sz.height = extents.cy; - delete [] dx; + delete[] dx; #elif defined(NANA_X11) sz = text_extent_size(str + begin, end - begin); #endif @@ -533,8 +640,8 @@ namespace paint bool graphics::glyph_pixels(const wchar_t * str, std::size_t len, unsigned* pxbuf) const { - if(nullptr == impl_->handle || nullptr == impl_->handle->context || nullptr == str || nullptr == pxbuf) return false; - if(len == 0) return true; + if (nullptr == impl_->handle || nullptr == impl_->handle->context || nullptr == str || nullptr == pxbuf) return false; + if (len == 0) return true; unsigned tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.whitespace_pixels; #if defined(NANA_WINDOWS) @@ -542,22 +649,22 @@ namespace paint SIZE extents; ::GetTextExtentExPoint(impl_->handle->context, str, static_cast(len), 0, 0, dx, &extents); - pxbuf[0] = (str[0] == '\t' ? tab_pixels : dx[0]); + pxbuf[0] = (str[0] == '\t' ? tab_pixels : dx[0]); - for(std::size_t i = 1; i < len; ++i) + for (std::size_t i = 1; i < len; ++i) { pxbuf[i] = (str[i] == '\t' ? tab_pixels : dx[i] - dx[i - 1]); } - delete [] dx; + delete[] dx; #elif defined(NANA_X11) && defined(NANA_USE_XFT) auto disp = nana::detail::platform_spec::instance().open_display(); auto xft = reinterpret_cast(impl_->handle->font->native_handle()); XGlyphInfo extents; - for(std::size_t i = 0; i < len; ++i) + for (std::size_t i = 0; i < len; ++i) { - if(str[i] != '\t') + if (str[i] != '\t') { FT_UInt glyphs = ::XftCharIndex(disp, xft, str[i]); ::XftGlyphExtents(disp, xft, &glyphs, 1, &extents); @@ -570,6 +677,9 @@ namespace paint return true; } +#endif + + nana::size graphics::bidi_extent_size(const std::wstring& str) const { nana::size sz; diff --git a/source/paint/text_renderer.cpp b/source/paint/text_renderer.cpp index b2848c2f..21a9157a 100644 --- a/source/paint/text_renderer.cpp +++ b/source/paint/text_renderer.cpp @@ -236,7 +236,12 @@ namespace nana std::unique_ptr pixel_buf(new unsigned[len]); //Find the char that should be splitted +#ifdef _nana_std_has_string_view + graph.glyph_pixels({ i.begin, len }, pixel_buf.get()); +#else graph.glyph_pixels(i.begin, len, pixel_buf.get()); +#endif + std::size_t idx_head = 0, idx_splitted; do @@ -456,7 +461,11 @@ namespace nana std::unique_ptr scope_res(new unsigned[len]); auto pxbuf = scope_res.get(); //Find the char that should be splitted +#ifdef _nana_std_has_string_view + graph.glyph_pixels({ i.begin, len }, pxbuf); +#else graph.glyph_pixels(i.begin, len, pxbuf); +#endif std::size_t idx_head = 0, idx_splitted; do @@ -636,12 +645,15 @@ namespace nana #ifdef _nana_std_has_string_view const auto ellipsis = graph_.text_extent_size(std::string_view{ "...", 3 }).width; + + std::unique_ptr pixels(new unsigned[text.size()]); + graph_.glyph_pixels({ text.c_str(), text.size() }, pixels.get()); #else const auto ellipsis = graph_.text_extent_size("...", 3).width; -#endif std::unique_ptr pixels(new unsigned[text.size()]); graph_.glyph_pixels(text.c_str(), text.size(), pixels.get()); +#endif std::size_t substr_len = 0; unsigned substr_px = 0;