Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions addons/ofxSvg/src/ofxSvg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ ofxSvg::ofxSvg(const of::filesystem::path & fileName) {

//--------------------------------------------------------------
bool ofxSvg::load( const of::filesystem::path& fileName ) {
ofFile mainXmlFile( fileName, ofFile::ReadOnly );
ofFile mainXmlFile( fileName, ofFile::ReadWrite );
ofBuffer tMainXmlBuffer( mainXmlFile );

svgPath = fileName;
Expand Down Expand Up @@ -1093,6 +1093,9 @@ void ofxSvg::_parsePolylinePolygon( ofXml& tnode, std::shared_ptr<ofxSvgPath> aS
aSvgPath->path.close();
}
}
if( aSvgPath ){
aSvgPath->getBoundingBox();
}
}
// reference: https://www.w3.org/TR/SVG2/paths.html#PathData
//--------------------------------------------------------------
Expand Down Expand Up @@ -1654,6 +1657,9 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {

justInCase++;
}
if( aSvgPath ){
aSvgPath->getBoundingBox();
}
}

//--------------------------------------------------------------
Expand Down Expand Up @@ -1806,7 +1812,7 @@ glm::mat4 ofxSvg::setTransformFromSvgMatrixString( string aStr, std::shared_ptr<

if( ofIsStringInString(aStr, "translate")) {
auto transStr = aStr;
auto tp = _parseMatrixString(transStr, "translate", false );
auto tp = _parseMatrixString(transStr, "translate", true );
tp.z = 0.f;
ofLogVerbose("ofxSvg::setTransformFromSvgMatrixString") << aele->getTypeAsString() << " name: " << aele->getName() << " translate: " << tp;
// apos += tp;
Expand Down Expand Up @@ -2172,6 +2178,9 @@ std::shared_ptr<ofxSvgPath> ofxSvg::add( const ofPath& apath ) {
auto path = std::make_shared<ofxSvgPath>();
path->path = apath;
path->applyStyle(mCurrentCss);

path->getBoundingBox(); //force the generation of the bounding box in the main thread.

_getPushedGroup()->add(path);
recalculateLayers();
mPaths.clear();
Expand Down
12 changes: 12 additions & 0 deletions addons/ofxSvg/src/ofxSvgCss.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,18 @@ std::string ofxSvgCssClass::toString(bool aBPrettyPrint) {
return ss.str();
}

//--------------------------------------------------
std::string ofxSvgCssClass::toString(bool aBPrettyPrint) const {
std::stringstream ss;
for( auto& piter : properties ) {
if(aBPrettyPrint) {
ss << std::endl << " ";
}
ss << piter.first << ":" << piter.second.srcString << ";";
}
return ss.str();
}

//--------------------------------------------------
bool ofxSvgCssStyleSheet::parse( std::string aCssString ) {
if( aCssString.empty() ) {
Expand Down
1 change: 1 addition & 0 deletions addons/ofxSvg/src/ofxSvgCss.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class ofxSvgCssClass {
ofColor getColor(const std::string& akey, const ofColor& adefault);

std::string toString(bool aBPrettyPrint=true);
std::string toString(bool aBPrettyPrint=true) const;

protected:
Property dummyProp;
Expand Down
135 changes: 107 additions & 28 deletions addons/ofxSvg/src/ofxSvgElements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ string ofxSvgElement::getCleanName() {
{std::regex("_x28_"), "("},
{std::regex("_x29_"), ")"},
{std::regex("_x3B_"), ";"},
{std::regex("_x2C_"), ","}
{std::regex("_x2C_"), ","},
{std::regex("_x5B_"), "["},
{std::regex("_x5D_"), "]"}
};

for (const auto& [regexPattern, replacement] : tregs) {
Expand Down Expand Up @@ -356,6 +358,21 @@ std::vector<std::string> ofxSvgText::splitWordsAndLineEndings(const std::string&
}

// build the text spans from a string and not from xml / svg file structure //
//--------------------------------------------------------------
void ofxSvgText::setText( const std::string& astring ) {
setText(astring, -1.f);
}

//--------------------------------------------------------------
void ofxSvgText::setText( const std::string& astring, float aMaxWidth ) {
if( textSpans.size() > 0 ) {
auto tspanClass = textSpans[0]->getCssClass();
setText(astring, tspanClass, aMaxWidth );
} else {
setText(astring, mSvgCssClass.getFontFamily("Arial"), mSvgCssClass.getFontSize(18), aMaxWidth );
}
}

//--------------------------------------------------------------
void ofxSvgText::setText( const std::string& astring, std::string aFontFamily, int aFontSize, float aMaxWidth ) {
ofxSvgCssClass css;
Expand All @@ -369,14 +386,19 @@ void ofxSvgText::setText( const std::string& astring, std::string aFontFamily, i
void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvgCssClass, float aMaxWidth ) {
meshes.clear();
textSpans.clear();

if( astring.empty() ) {
ofLogWarning("ofxSvgText::setText") << "string argument is empty. ";
return;
}

// set the true for debugging.
bool bVerbose = false;

bool bCreateNewTextSpanPerLine = mBCreateNewTextSpanPerLine;

auto spanStrings = splitBySpanTags(astring);
// ofLogNotice("ofxSvgText") << "number of strings: " << spanStrings.size();
// ofLogNotice("ofxSvgText") << "number of strings: " << spanStrings.size();
float ex = 0.f;
float ey = 0.f;
int spanCounter = 0;
Expand All @@ -396,9 +418,11 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg
// css.addProperty("color", getColor() );
if (spanString.find("<span") != std::string::npos) {
SpanData data = extractSpanData(spanString);
// std::cout << "Found <span> tag.\n";
// std::cout << " Style: [" << data.style << "]\n";
// std::cout << " Content: [" << data.content << "]\n";
if(bVerbose) {
std::cout << "Found <span> tag.\n";
std::cout << " Style: [" << data.style << "]\n";
std::cout << " Content: [" << data.content << "]\n";
}
css.addProperties(data.style);
if (!data.content.empty() && data.content.back() == ' ') {
bLastCharIsSpace = true;
Expand All @@ -421,9 +445,40 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg

auto cspan = std::make_shared<ofxSvgText::TextSpan>();
cspan->applyStyle(css);

ofLogVerbose("ofxSvgText" ) << "going to try and load: " << spanString << " bold: " << cspan->isBold() << " italic: " << cspan->isItalic();
if(!ofxSvgFontBook::loadFont(fdirectory, cspan->getFontFamily(), cspan->getFontSize(), cspan->isBold(), cspan->isItalic() )) {
if( spanStrings.size() > 1 ) {
if(bVerbose) {
std::cout << "-------------------------------------" << std::endl;
ofLogNotice("ofxSvgText" ) << "going to try and load: " << spanString << std::endl << "css: " << css.toString();
for( auto& tw : twords ) {
std::cout << "|" << tw << "|";
}
std::cout << std::endl << "-------------------------------------" << std::endl;
}
}

// build a quick string from the words.
std::string tempStr;
for( auto& tw : twords ) {
tempStr += tw;
}

// if(!ofxSvgFontBook::loadFont(fdirectory, cspan->getFontFamily(), cspan->getFontSize(), cspan->isBold(), cspan->isItalic() )) {
ofTrueTypeFontSettings fsettings(fdirectory, cspan->getFontSize());
// now determine if there is other languages to load.
// TODO: Add more language support.
auto detectedLang = ofxSvgFontBook::detectLanguage(tempStr);
if( detectedLang == ofxSvgFontBook::TextLanguage::JAPANESE ) {
fsettings.addRanges(ofAlphabet::Japanese);
} else if( detectedLang == ofxSvgFontBook::TextLanguage::CHINESE ) {
fsettings.addRanges(ofAlphabet::Chinese);
} else if( detectedLang == ofxSvgFontBook::TextLanguage::KOREAN ) {
fsettings.addRanges(ofAlphabet::Korean);
}

if( !ofxSvgFontBook::loadFont(fdirectory, cspan->getCssClass(), fsettings )) {

continue;
}

Expand Down Expand Up @@ -453,21 +508,6 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg

bool bWasAStringLineBreak = false;

// std::cout << "_____________________________________________________" << std::endl;
// for( std::size_t i = 0; i < twords.size(); i++ ) {
// auto& token = twords[i];
// if (token == "\n") {
// std::cout << "[\\n]" << std::endl;
// } else if (token == "\r\n") {
// std::cout << "[\\r\\n]" << std::endl;
// } else if (token == "\r") {
// std::cout << "[\\r]" << std::endl;
// } else {
// std::cout << "[" << token << "]" << std::endl;
// }
// }
// std::cout << "_____________________________________________________" << std::endl;

for( std::size_t i = 0; i < twords.size(); i++ ) {

bool bFinalWord = (i == twords.size()-1);
Expand All @@ -490,7 +530,7 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg
// ofLogNotice("textSpan word string") << "|"<<tCurrentString << "|";;
// ex = font.stringWidth(tCurrentString);
ex = font.getStringBoundingBox(tCurrentString,0,0,true).getRight();
if(ex + cspan->rect.x > aMaxWidth || bIsAStringLineBreak > 0 ) {
if( (aMaxWidth > 0.f && ex + cspan->rect.x > aMaxWidth) || bIsAStringLineBreak > 0 ) {
// if( ex > aMaxWidth ) {

tCurrentString = twords[i];
Expand All @@ -517,7 +557,12 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg
ey += font.getLineHeight();

if( ss.str().size() > 0 ) {
// ofLogNotice("ofxSvgText") << "LINE Break: adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|";
// ofLogNotice("ofxSvgText") << "LINE Break: adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|";
if( spanStrings.size() > 1 ) {
if(bVerbose) {
ofLogNotice("ofxSvgText") << "LINE Break: adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|";
}
}
textSpans.push_back(cspan);
}

Expand All @@ -535,10 +580,30 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg
//ey += font.stringHeight("M");
bAddedBreak = true;
if( spanCounter == 0 && i == 0 ) {

cspan->text = ss.str();
} else {
ey += font.getLineHeight();
ss << std::endl;
if(bCreateNewTextSpanPerLine) {
cspan->text = ss.str();
if( ss.str().size() > 0 ) {
if( spanStrings.size() > 1 ) {
if(bVerbose) {
ofLogNotice("ofxSvgText") << "LINE Break: adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|";
}
}
textSpans.push_back(cspan);
}

cspan = std::make_shared<ofxSvgText::TextSpan>();
cspan->applyStyle(css);
ss.str("");
ss.clear();
// ofLogNotice("Adding a new line I think") << "ss: " <<ss.str();
// cspan->rect.x = ex;
cspan->rect.y = ey;
} else {
ss << std::endl;
}
}
}

Expand Down Expand Up @@ -582,7 +647,7 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg
// ex += font.getCharWidth('f');
// }
cspan->text = ss.str();
// ofLogNotice("ofxSvgText") << "adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|";
// ofLogNotice("ofxSvgText") << "adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|";
cspan->rect.height = font.getStringBoundingBox(cspan->text, 0.f, 0.f ).getHeight();//font.stringHeight(cspan->text);
if( bFirstBreak ) {
cspan->rect.height = font.getLineHeight();
Expand All @@ -592,6 +657,11 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg
}
// ey = cspan->rect.y + cspan->rect.height;
//ey += cspan->rect.height;
if( spanStrings.size() > 1 ) {
if(bVerbose) {
ofLogNotice("ofxSvgText") << "Adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|";
}
}
textSpans.push_back(cspan);
}

Expand All @@ -605,6 +675,15 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg
create();
}

//--------------------------------------------------------------
void ofxSvgText::updateText( const std::string& astring, float aMaxWidth) {
if( textSpans.size() ){
auto css = textSpans[0]->getCssClass();
setText( astring, css, aMaxWidth );
}
}


//--------------------------------------------------------------
void ofxSvgText::create() {
meshes.clear();
Expand Down
21 changes: 20 additions & 1 deletion addons/ofxSvg/src/ofxSvgElements.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,11 @@ class ofxSvgPath : public ofxSvgElement {
}
}

if( path.getCommands().size() && outlines.size() == 0 ){
ofLogError("ofxSvgPath::getBoundingBox()" ) << " path outline size is 0 - you may need to call this function in a main thread to get the correct bounds ";
mBBoxNeedsRecalc = true;
}

path.setStrokeWidth(prevStrokeWidth);
}
return mBounds;
Expand Down Expand Up @@ -576,9 +581,12 @@ class ofxSvgText : public ofxSvgElement {
virtual ofxSvgType getType() override {return OFXSVG_TYPE_TEXT;}

ofTrueTypeFont& getFont();

void setText( const std::string& astring );
void setText( const std::string& astring, float aMaxWidth );
void setText( const std::string& astring, std::string aFontFamily, int aFontSize, float aMaxWidth );
void setText( const std::string& astring, const ofxSvgCssClass& aSvgCssClass, float aMaxWidth );
void updateText( const std::string& astring, float aMaxWidth);

void create();
void customDraw() override;
// going to override
Expand Down Expand Up @@ -622,6 +630,15 @@ class ofxSvgText : public ofxSvgElement {
}
}

/// \ brief Applied when calling setText()
void setCreateNewTextSpansPerLine(bool ab) {
mBCreateNewTextSpanPerLine = ab;
}

bool isCreatingNewTextSpanPerLine() {
return mBCreateNewTextSpanPerLine;
}

/// \brief Get the local bounding box of all of the text spans.
virtual ofRectangle getBoundingBox() override;

Expand Down Expand Up @@ -661,6 +678,8 @@ class ofxSvgText : public ofxSvgElement {
bool endsWithLineEnding(const std::string& astr);
std::vector<std::string> splitWordsAndLineEndings(const std::string& input);

bool mBCreateNewTextSpanPerLine = false;

};


Expand Down
Loading
Loading