mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-06 12:39:57 +00:00
Replace utf8 iterators with utf8_decode (fix #3260)
This should fix some problems decoding invalid UTF-8 strings.
This commit is contained in:
parent
75a99360a0
commit
65ef6f8e96
2
laf
2
laf
@ -1 +1 @@
|
||||
Subproject commit 4f4693a8e63b7bc63e3c0825112f7f3f190ebee9
|
||||
Subproject commit df53f4ac0cecada789bf84b4283947d2591833bd
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -9,9 +10,7 @@
|
||||
#endif
|
||||
|
||||
#include "app/file/split_filename.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/string.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@ -20,41 +19,44 @@ namespace app {
|
||||
// Splits a file-name like "my_ani0000.pcx" to "my_ani" and ".pcx",
|
||||
// returning the number of the center; returns "-1" if the function
|
||||
// can't split anything
|
||||
int split_filename(const std::string& filename, std::string& left, std::string& right, int& width)
|
||||
int split_filename(const std::string& filename,
|
||||
std::string& left,
|
||||
std::string& right,
|
||||
int& width)
|
||||
{
|
||||
left = base::get_file_title_with_path(filename);
|
||||
right = base::get_file_extension(filename);
|
||||
if (!right.empty())
|
||||
right.insert(right.begin(), '.');
|
||||
|
||||
// Remove all trailing numbers in the "left" side, and pass they to "result_str".
|
||||
// Remove all trailing numbers in the "left" side.
|
||||
std::string result_str;
|
||||
width = 0;
|
||||
for (;;) {
|
||||
// Get the last UTF-8 character (as we don't have a
|
||||
// reverse_iterator, we iterate from the beginning)
|
||||
int chr = 0;
|
||||
base::utf8_const_iterator begin(left.begin()), end(left.end());
|
||||
base::utf8_const_iterator it(begin), prev(begin);
|
||||
for (; it != end; prev=it, ++it)
|
||||
chr = *it;
|
||||
int num = -1;
|
||||
int order = 1;
|
||||
|
||||
if ((chr >= '0') && (chr <= '9')) {
|
||||
result_str.insert(result_str.begin(), chr);
|
||||
width++;
|
||||
auto it = left.rbegin();
|
||||
auto end = left.rend();
|
||||
|
||||
left.erase(prev - begin);
|
||||
while (it != end) {
|
||||
const int chr = *it;
|
||||
if (chr >= '0' && chr <= '9') {
|
||||
if (num < 0)
|
||||
num = 0;
|
||||
|
||||
num += order*(chr-'0');
|
||||
order *= 10;
|
||||
++width;
|
||||
++it;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// Convert the "buf" to integer and return it.
|
||||
if (!result_str.empty()) {
|
||||
return base::convert_to<int>(result_str);
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
if (width > 0)
|
||||
left.erase(left.end()-width, left.end());
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -12,7 +13,10 @@
|
||||
|
||||
namespace app {
|
||||
|
||||
int split_filename(const std::string& filename, std::string& left, std::string& right, int& width);
|
||||
int split_filename(const std::string& filename,
|
||||
std::string& left,
|
||||
std::string& right,
|
||||
int& width);
|
||||
|
||||
} // namespace app
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -17,11 +18,21 @@ TEST(SplitFilename, Common)
|
||||
std::string left, right;
|
||||
int width;
|
||||
|
||||
EXPECT_EQ(-1, split_filename("sprite.png", left, right, width));
|
||||
EXPECT_EQ("sprite", left);
|
||||
EXPECT_EQ(".png", right);
|
||||
EXPECT_EQ(0, width);
|
||||
|
||||
EXPECT_EQ(1, split_filename("C:\\test\\a1.png", left, right, width));
|
||||
EXPECT_EQ("C:\\test\\a", left);
|
||||
EXPECT_EQ(".png", right);
|
||||
EXPECT_EQ(1, width);
|
||||
|
||||
EXPECT_EQ(2001, split_filename("/hi/bye2001.png", left, right, width));
|
||||
EXPECT_EQ("/hi/bye", left);
|
||||
EXPECT_EQ(".png", right);
|
||||
EXPECT_EQ(4, width);
|
||||
|
||||
EXPECT_EQ(1, split_filename("C:/test/a1.png", left, right, width));
|
||||
EXPECT_EQ("C:/test/a", left);
|
||||
EXPECT_EQ(".png", right);
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "base/fs.h"
|
||||
#include "base/log.h"
|
||||
#include "base/string.h"
|
||||
#include "base/utf8_decode.h"
|
||||
#include "gfx/border.h"
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/rect.h"
|
||||
@ -1131,14 +1132,13 @@ void SkinTheme::drawEntryText(ui::Graphics* g, ui::Entry* widget)
|
||||
int scroll = delegate.index();
|
||||
|
||||
const std::string& textString = widget->text();
|
||||
base::utf8_const_iterator utf8_it((textString.begin()));
|
||||
int textlen = base::utf8_length(textString);
|
||||
scroll = std::min(scroll, textlen);
|
||||
if (scroll)
|
||||
utf8_it += scroll;
|
||||
base::utf8_decode dec(textString);
|
||||
auto pos = dec.pos();
|
||||
for (int i=0; i<scroll && dec.next(); ++i)
|
||||
pos = dec.pos();
|
||||
|
||||
g->drawText(utf8_it,
|
||||
base::utf8_const_iterator(textString.end()),
|
||||
// TODO use a string_view()
|
||||
g->drawText(std::string(pos, textString.end()),
|
||||
colors.text(), ColorNone,
|
||||
bounds.origin(), &delegate);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2022 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -47,52 +48,49 @@ doc::Image* render_text(const std::string& fontfile, int fontsize,
|
||||
image.reset(doc::Image::create(doc::IMAGE_RGB, bounds.w, bounds.h));
|
||||
doc::clear_image(image.get(), 0);
|
||||
|
||||
ft::ForEachGlyph<ft::Face> feg(face);
|
||||
if (feg.initialize(base::utf8_const_iterator(text.begin()),
|
||||
base::utf8_const_iterator(text.end()))) {
|
||||
do {
|
||||
auto glyph = feg.glyph();
|
||||
if (!glyph)
|
||||
continue;
|
||||
ft::ForEachGlyph<ft::Face> feg(face, text);
|
||||
while (feg.next()) {
|
||||
auto glyph = feg.glyph();
|
||||
if (!glyph)
|
||||
continue;
|
||||
|
||||
int t, yimg = - bounds.y + int(glyph->y);
|
||||
int t, yimg = - bounds.y + int(glyph->y);
|
||||
|
||||
for (int v=0; v<int(glyph->bitmap->rows); ++v, ++yimg) {
|
||||
const uint8_t* p = glyph->bitmap->buffer + v*glyph->bitmap->pitch;
|
||||
int ximg = - bounds.x + int(glyph->x);
|
||||
int bit = 0;
|
||||
for (int v=0; v<int(glyph->bitmap->rows); ++v, ++yimg) {
|
||||
const uint8_t* p = glyph->bitmap->buffer + v*glyph->bitmap->pitch;
|
||||
int ximg = - bounds.x + int(glyph->x);
|
||||
int bit = 0;
|
||||
|
||||
for (int u=0; u<int(glyph->bitmap->width); ++u, ++ximg) {
|
||||
int alpha;
|
||||
for (int u=0; u<int(glyph->bitmap->width); ++u, ++ximg) {
|
||||
int alpha;
|
||||
|
||||
if (antialias) {
|
||||
alpha = *(p++);
|
||||
}
|
||||
else {
|
||||
alpha = ((*p) & (1 << (7 - (bit++))) ? 255: 0);
|
||||
if (bit == 8) {
|
||||
bit = 0;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
int output_alpha = MUL_UN8(doc::rgba_geta(color), alpha, t);
|
||||
if (output_alpha) {
|
||||
doc::color_t output_color =
|
||||
doc::rgba(doc::rgba_getr(color),
|
||||
doc::rgba_getg(color),
|
||||
doc::rgba_getb(color),
|
||||
output_alpha);
|
||||
|
||||
doc::put_pixel(
|
||||
image.get(), ximg, yimg,
|
||||
doc::rgba_blender_normal(
|
||||
doc::get_pixel(image.get(), ximg, yimg),
|
||||
output_color));
|
||||
if (antialias) {
|
||||
alpha = *(p++);
|
||||
}
|
||||
else {
|
||||
alpha = ((*p) & (1 << (7 - (bit++))) ? 255: 0);
|
||||
if (bit == 8) {
|
||||
bit = 0;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
int output_alpha = MUL_UN8(doc::rgba_geta(color), alpha, t);
|
||||
if (output_alpha) {
|
||||
doc::color_t output_color =
|
||||
doc::rgba(doc::rgba_getr(color),
|
||||
doc::rgba_getg(color),
|
||||
doc::rgba_getb(color),
|
||||
output_alpha);
|
||||
|
||||
doc::put_pixel(
|
||||
image.get(), ximg, yimg,
|
||||
doc::rgba_blender_normal(
|
||||
doc::get_pixel(image.get(), ximg, yimg),
|
||||
output_color));
|
||||
}
|
||||
}
|
||||
} while (feg.nextChar());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -922,9 +922,7 @@ void Entry::recalcCharBoxes(const std::string& text)
|
||||
{
|
||||
int lastTextIndex = int(text.size());
|
||||
CalcBoxesTextDelegate delegate(lastTextIndex);
|
||||
os::draw_text(nullptr, font(),
|
||||
base::utf8_const_iterator(text.begin()),
|
||||
base::utf8_const_iterator(text.end()),
|
||||
os::draw_text(nullptr, font(), text,
|
||||
gfx::ColorNone, gfx::ColorNone, 0, 0, &delegate);
|
||||
m_boxes = delegate.boxes();
|
||||
|
||||
|
@ -362,8 +362,7 @@ void Graphics::setFont(const os::FontRef& font)
|
||||
m_font = font;
|
||||
}
|
||||
|
||||
void Graphics::drawText(base::utf8_const_iterator it,
|
||||
const base::utf8_const_iterator& end,
|
||||
void Graphics::drawText(const std::string& str,
|
||||
gfx::Color fg, gfx::Color bg,
|
||||
const gfx::Point& origPt,
|
||||
os::DrawTextDelegate* delegate)
|
||||
@ -372,18 +371,11 @@ void Graphics::drawText(base::utf8_const_iterator it,
|
||||
|
||||
os::SurfaceLock lock(m_surface.get());
|
||||
gfx::Rect textBounds =
|
||||
os::draw_text(m_surface.get(), m_font.get(), it, end, fg, bg, pt.x, pt.y, delegate);
|
||||
os::draw_text(m_surface.get(), m_font.get(), str, fg, bg, pt.x, pt.y, delegate);
|
||||
|
||||
dirty(gfx::Rect(pt.x, pt.y, textBounds.w, textBounds.h));
|
||||
}
|
||||
|
||||
void Graphics::drawText(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& pt)
|
||||
{
|
||||
drawText(base::utf8_const_iterator(str.begin()),
|
||||
base::utf8_const_iterator(str.end()),
|
||||
fg, bg, pt, nullptr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class DrawUITextDelegate : public os::DrawTextDelegate {
|
||||
@ -457,10 +449,8 @@ void Graphics::drawUIText(const std::string& str, gfx::Color fg, gfx::Color bg,
|
||||
int y = m_dy+pt.y;
|
||||
|
||||
DrawUITextDelegate delegate(m_surface.get(), m_font.get(), mnemonic);
|
||||
os::draw_text(m_surface.get(), m_font.get(),
|
||||
base::utf8_const_iterator(str.begin()),
|
||||
base::utf8_const_iterator(str.end()),
|
||||
fg, bg, x, y, &delegate);
|
||||
os::draw_text(m_surface.get(), m_font.get(), str,
|
||||
fg, bg, x, y, &delegate);
|
||||
|
||||
dirty(delegate.bounds());
|
||||
}
|
||||
@ -482,11 +472,9 @@ gfx::Size Graphics::measureUIText(const std::string& str)
|
||||
int Graphics::measureUITextLength(const std::string& str, os::Font* font)
|
||||
{
|
||||
DrawUITextDelegate delegate(nullptr, font, 0);
|
||||
os::draw_text(nullptr, font,
|
||||
base::utf8_const_iterator(str.begin()),
|
||||
base::utf8_const_iterator(str.end()),
|
||||
gfx::ColorNone, gfx::ColorNone, 0, 0,
|
||||
&delegate);
|
||||
os::draw_text(nullptr, font, str,
|
||||
gfx::ColorNone, gfx::ColorNone, 0, 0,
|
||||
&delegate);
|
||||
return delegate.bounds().w;
|
||||
}
|
||||
|
||||
|
@ -117,11 +117,10 @@ namespace ui {
|
||||
os::Font* font() { return m_font.get(); }
|
||||
void setFont(const os::FontRef& font);
|
||||
|
||||
void drawText(base::utf8_const_iterator it,
|
||||
const base::utf8_const_iterator& end,
|
||||
gfx::Color fg, gfx::Color bg, const gfx::Point& pt,
|
||||
os::DrawTextDelegate* delegate);
|
||||
void drawText(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& pt);
|
||||
void drawText(const std::string& str,
|
||||
gfx::Color fg, gfx::Color bg,
|
||||
const gfx::Point& pt,
|
||||
os::DrawTextDelegate* delegate = nullptr);
|
||||
void drawUIText(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Point& pt, const int mnemonic);
|
||||
void drawAlignedUIText(const std::string& str, gfx::Color fg, gfx::Color bg, const gfx::Rect& rc, const int align);
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "base/clamp.h"
|
||||
#include "base/memory.h"
|
||||
#include "base/string.h"
|
||||
#include "base/utf8_decode.h"
|
||||
#include "os/font.h"
|
||||
#include "os/surface.h"
|
||||
#include "os/system.h"
|
||||
@ -1400,19 +1401,18 @@ void Widget::processMnemonicFromText(int escapeChar)
|
||||
if (!m_text.empty())
|
||||
newText.reserve(m_text.size());
|
||||
|
||||
for (base::utf8_const_iterator
|
||||
it(m_text.begin()),
|
||||
end(m_text.end()); it != end; ++it) {
|
||||
if (*it == escapeChar) {
|
||||
++it;
|
||||
if (it == end) {
|
||||
base::utf8_decode decode(m_text);
|
||||
while (int chr = decode.next()) {
|
||||
if (chr == escapeChar) {
|
||||
chr = decode.next();
|
||||
if (!chr) {
|
||||
break; // Ill-formed string (it ends with escape character)
|
||||
}
|
||||
else if (*it != escapeChar) {
|
||||
setMnemonic(*it);
|
||||
else if (chr != escapeChar) {
|
||||
setMnemonic(chr);
|
||||
}
|
||||
}
|
||||
newText.push_back(*it);
|
||||
newText.push_back(chr);
|
||||
}
|
||||
|
||||
setText(base::to_utf8(newText));
|
||||
|
Loading…
x
Reference in New Issue
Block a user