Skip to content

Commit

Permalink
fix poor or missing svg thumbnails when selecting images to insert
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinhendricks committed Feb 15, 2024
1 parent 9cb9d74 commit d889311
Show file tree
Hide file tree
Showing 11 changed files with 713 additions and 17 deletions.
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#
#########################################################

cmake_minimum_required( VERSION 3.0.0 )
cmake_minimum_required( VERSION 3.0.5 )

#############################################################################

Expand Down Expand Up @@ -46,8 +46,8 @@ set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib )

set( PAGEEDIT_MAJOR_VERSION 2 )
set( PAGEEDIT_MINOR_VERSION 0 )
set( PAGEEDIT_REVISION_VERSION 2 )
set( PAGEEDIT_MINOR_VERSION 1 )
set( PAGEEDIT_REVISION_VERSION 0 )
set( PAGEEDIT_FULL_VERSION ${PAGEEDIT_MAJOR_VERSION}.${PAGEEDIT_MINOR_VERSION}.${PAGEEDIT_REVISION_VERSION} )

if( UNIX AND NOT APPLE )
Expand Down
8 changes: 6 additions & 2 deletions CMakeLists5.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ else()
# Qt5 packages minimum version 5.12 for Windows/Mac
set(QT5_NEEDED 5.12)
endif()
find_package(Qt5 ${QT5_NEEDED} COMPONENTS Core Network WebEngine WebEngineWidgets Widgets PrintSupport Xml LinguistTools)
find_package(Qt5 ${QT5_NEEDED} COMPONENTS Core Network WebEngine WebEngineWidgets Svg Widgets PrintSupport Xml LinguistTools)
set(CMAKE_AUTOMOC ON)

set( SOURCE_FILES
Expand Down Expand Up @@ -53,6 +53,8 @@ set( SOURCE_FILES
ClipsWindow.cpp
ClassInfo.cpp
WebProfileMgr.cpp
TagAtts.cpp
QuickParser.cpp
)

set( HEADER_FILES
Expand Down Expand Up @@ -94,6 +96,8 @@ set( HEADER_FILES
ClipsWindow.h
ClassInfo.h
WebProfileMgr.h
TagAtts.h
QuickParser.h
)

set( FORM_FILES
Expand Down Expand Up @@ -231,7 +235,7 @@ endif()

# No need to explicity link Qt5::WinMain or to use the qt5_use_modules macro since CMAKE 2.8.11. We require CMAKE 3.0.0
target_link_libraries( ${PROJECT_NAME} ${GUMBO_LIBRARIES} Qt5::Widgets Qt5::Xml Qt5::PrintSupport
Qt5::WebEngine Qt5::WebEngineWidgets Qt5::Network )
Qt5::WebEngine Qt5::WebEngineWidgets Qt5::Svg Qt5::Network )

#############################################################################

Expand Down
8 changes: 6 additions & 2 deletions CMakeLists6.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ else()
# Qt6 packages minimum version 5.12 for Windows/Mac
set(QT6_NEEDED 6.2)
endif()
find_package(Qt6 ${QT6_NEEDED} COMPONENTS Core5Compat Network WebEngineCore WebEngineWidgets Widgets Xml PrintSupport LinguistTools)
find_package(Qt6 ${QT6_NEEDED} COMPONENTS Core5Compat Network WebEngineCore WebEngineWidgets Svg Widgets Xml PrintSupport LinguistTools)
set(CMAKE_AUTOMOC ON)

set( SOURCE_FILES
Expand Down Expand Up @@ -60,6 +60,8 @@ set( SOURCE_FILES
ClipsWindow.cpp
ClassInfo.cpp
WebProfileMgr.cpp
TagAtts.cpp
QuickParser.cpp
)

set( HEADER_FILES
Expand Down Expand Up @@ -101,6 +103,8 @@ set( HEADER_FILES
ClipsWindow.h
ClassInfo.h
WebProfileMgr.h
TagAtts.h
QuickParser.h
)

set( FORM_FILES
Expand Down Expand Up @@ -237,7 +241,7 @@ endif()

# No need to explicity link Qt6::WinMain or to use the qt6_use_modules macro since CMAKE 2.8.11. We require CMAKE 3.0.0
target_link_libraries( ${PROJECT_NAME} ${GUMBO_LIBRARIES} Qt6::Core5Compat Qt6::Widgets Qt6::PrintSupport
Qt6::WebEngineCore Qt6::WebEngineWidgets Qt6::Network)
Qt6::WebEngineCore Qt6::WebEngineWidgets Qt6::Svg Qt6::Network)

#############################################################################

Expand Down
11 changes: 8 additions & 3 deletions ChangeLog.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
Change Log
==========
PageEdit-pre2.X.X
PageEdit-2.1.0
Bug Fixes
- fixes for numerous Qt related bug and security issues via update to Qt 6.6.2
- fix poor or missing svg rendering of thumbnails when selecting images to insert

New Features
- Improved Accessibility support via Qt, especially for users on macOS


PageEdit-2.02
PageEdit-2.0.2
Bug Fixes
- workaround QtWebEngine load Finished signal not indicating when javascript is ready
- remove previous hack for missing loadFinished after loadStarted during internal links
Expand All @@ -15,7 +20,7 @@ PageEdit-2.02
- add workaround Edit->Paste of html from clipboard without full context on Windows


PageEdit-2.00
PageEdit-2.0.0
New Features
- updated official releases to use Qt 6.5.2
- added ability to create and apply Clips
Expand Down
275 changes: 275 additions & 0 deletions QuickParser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
/************************************************************************
**
** Copyright (C) 2024 Kevin B. Hendricks, Stratford Ontario
**
** This file is part of PageEdit.
**
** PageEdit is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** PageEdit is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with PageEdit. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/

#include <QChar>
#include <QString>
#include <QStringList>
#include <QStringRef>
#include <QDebug>

#include "TagAtts.h"
#include "Utility.h"
#include "QuickParser.h"

const QString WHITESPACE_CHARS=" \v\t\n\r\f";

QuickParser::QuickParser(const QString &source, QString default_lang)
: m_source(source),
m_pos(0),
m_next(0)
{
m_LangPath << default_lang;
m_TagPath << "root";
}



// public interface


void QuickParser::reload_parser(const QString& source, QString default_language)
{
m_source = source;
m_pos = 0;
m_next = 0;
m_LangPath = QStringList() << default_language;
m_TagPath = QStringList() << "root";
}


QuickParser::MarkupInfo QuickParser::parse_next()
{
MarkupInfo mi;
mi.pos = -1;
QStringRef markup = parseML();
if (!markup.isNull()) {
if ((markup.at(0) == '<') && (markup.at(markup.size() - 1) == '>')) {
parseTag(markup, mi);
if (mi.ttype == "begin") {
m_TagPath << mi.tname;
QString lang = mi.tattr.value("lang", QString());
if (lang.isEmpty()) lang = mi.tattr.value("xml:lang", QString());
if (lang.isEmpty()) lang = m_LangPath.last();
m_LangPath << lang;
} else if (mi.ttype == "end") {
m_TagPath.removeLast();
m_LangPath.removeLast();
}
} else {
mi.text = markup.toString();
}
mi.pos = m_pos;
mi.lang = m_LangPath.last();
mi.tpath = m_TagPath.join(".");
}
return mi;
}


// Note all text and attribute values must be properly xml encoded if needed
QString QuickParser::serialize_markup(const QuickParser::MarkupInfo& mi)
{
QString res;
// handle leading text
if (!mi.text.isEmpty()) {
res = mi.text;
}

// if not tag info provided return just the text
if (mi.ttype.isEmpty() || mi.tname.isEmpty()) return res;

// handle any end tags
if (mi.ttype == "end") {
res = res + "</" + mi.tname + ">";
return res;
}

// handle the special cases
if ((mi.ttype == "xmlheader") || (mi.ttype == "doctype") || (mi.ttype == "pi")) {
res = res + "<" + mi.tname + mi.tattr["special"] + ">";
return res;
}
if (mi.ttype == "comment") {
res = res + "<" + mi.tname + mi.tattr["special"] + "-->";
return res;
}
if (mi.ttype == "cdata") {
res = res + "<" + mi.tname + mi.tattr["special"] + "]]>";
return res;
}
// finally begin and single tags
res = res + "<" + mi.tname;
foreach(QString key, mi.tattr.keys()) {
QString val = mi.tattr[key];
if (val.contains("\"")) {
res = res + " " + key + "=" + "'" + val + "'";
} else {
res = res + " " + key + "=" + "\"" + val + "\"";
}
}
if (mi.ttype == "single") {
res = res + "/>";
} else {
res = res + ">";
}
return res;
}


// private routines


QStringRef QuickParser::parseML()
{
int p = m_next;
m_pos = p;
if (p >= m_source.length()) return QStringRef();
if (m_source.at(p) != '<') {
// we have text leading up to a tag start
m_next = findTarget("<", p+1);
return Utility::SubstringRef(m_pos, m_next, m_source);
}
// we have a tag or special case
// handle special cases first
QString tstart = Utility::Substring(p, p+9, m_source);
if (tstart.startsWith("<!--")) {
// include ending > as part of the string
m_next = findTarget("-->", p+4, true);
return Utility::SubstringRef(m_pos, m_next, m_source);
}
if (tstart.startsWith("<![CDATA[")) {
// include ending > as part of the string
m_next = findTarget("]]>", p+9, true);
return Utility::SubstringRef(m_pos, m_next, m_source);
}
// include ending > as part of the string
m_next = findTarget(">", p+1, true);

int ntb = findTarget("<", p+1);
if ((ntb != -1) && (ntb < m_next)) {
m_next = ntb;
}
return Utility::SubstringRef(m_pos, m_next, m_source);
}


void QuickParser::parseTag(const QStringRef& tagstring, QuickParser::MarkupInfo& mi)
{
Q_ASSERT(tagstring.at(0) == '<');
Q_ASSERT(tagstring.at(tagstring.size() - 1) == '>');
int taglen = tagstring.length();
QChar c = tagstring.at(1);
int p = 0;

// first handle special cases
if (c == '?') {
if (tagstring.startsWith("<?xml")) {
mi.tname = "?xml";
mi.ttype = "xmlheader";
mi.tattr["special"] = Utility::Substring(5, taglen-1, tagstring);
} else {
mi.tname = "?";
mi.ttype = "pi";
mi.tattr["special"] = Utility::Substring(1, taglen-1, tagstring);
}
return;
}
if (c == '!') {
if (tagstring.startsWith("<!--")) {
mi.tname = "!--";
mi.ttype = "comment";
mi.tattr["special"] = Utility::Substring(4, taglen-3, tagstring);
} else if (tagstring.startsWith("<!DOCTYPE") || tagstring.startsWith("<!doctype")) {
mi.tname = "!DOCTYPE";
mi.ttype = "doctype";
mi.tattr["special"] = Utility::Substring(9, taglen-1, tagstring);
} else if (tagstring.startsWith("<![CDATA[") || tagstring.startsWith("<![cdata[")) {
mi.tname = "![CDATA[";
mi.ttype = "cdata";
mi.tattr["special"] = Utility::Substring(9, taglen-3, tagstring);
}
return;
}

// normal tag, extract tag name
p = skipAnyBlanks(tagstring, 1);
if (tagstring.at(p) == '/') {
mi.ttype = "end";
p++;
p = skipAnyBlanks(tagstring, p);
}
int b = p;
p = stopWhenContains(tagstring, ">/ \f\t\r\n", p);
mi.tname = Utility::Substring(b, p, tagstring);

// handle the possibility of attributes (so begin or single tag type, not end)
if (mi.ttype.isEmpty()) {
while (tagstring.indexOf("=", p) != -1) {
p = skipAnyBlanks(tagstring, p);
b = p;
p = stopWhenContains(tagstring, "=", p);
QString aname = Utility::Substring(b, p, tagstring).trimmed();
QString avalue;
p++;
p = skipAnyBlanks(tagstring, p);
if ((tagstring.at(p) == '\'') || (tagstring.at(p) == '"')) {
QString qc = tagstring.at(p);
p++;
b = p;
p = stopWhenContains(tagstring, qc, p);
avalue = Utility::Substring(b, p, tagstring);
p++;
} else {
b = p;
p = stopWhenContains(tagstring, ">/ ", p);
avalue = Utility::Substring(b, p, tagstring);
}
mi.tattr[aname] = avalue;
}
mi.ttype = "begin";
if (tagstring.indexOf("/", p) >= 0) mi.ttype = "single";
}
return;
}


int QuickParser::findTarget(const QString &tgt, int p, bool after)
{
int nxt = m_source.indexOf(tgt, p);
if (nxt == -1) return m_source.length();
nxt = nxt + (tgt.length() -1);
if (after) nxt++;
return nxt;
}


int QuickParser::skipAnyBlanks(const QStringRef &tgt, int p)
{
while((p < tgt.length()) && (WHITESPACE_CHARS.contains(tgt.at(p)))) p++;
return p;
}


int QuickParser::stopWhenContains(const QStringRef &tgt, const QString& stopchars, int p)
{
while((p < tgt.length()) && !stopchars.contains(tgt.at(p))) p++;
return p;
}
Loading

0 comments on commit d889311

Please sign in to comment.