static bool ParseFontFamily(const char* s, size_t len, FontID& v) { bool onFont = false; char buf[64]; size_t bufPos = 0; for (size_t i = 0; true; i++) { if (onFont) { if (s[i] == ',' || i == len) { buf[bufPos] = 0; v = Global()->FontStore->InsertByFacename(buf); if (v != FontIDNull) return true; onFont = false; bufPos = 0; } else { buf[bufPos++] = s[i]; } if (i == len) break; } else { if (i == len) break; if (IsWhitespace(s[i])) continue; onFont = true; buf[bufPos++] = s[i]; } if (bufPos >= arraysize(buf)) { ParseFail("Parse failed, font name too long (>63): '%*.s'\n", (int) len, s); return false; } } // not sure whether we should do this. One might want no font to be set instead. v = Global()->FontStore->GetFallbackFontID(); return true; }
bool Color::Parse(const char* s, size_t len, Color& v) { Color c = Color::RGBA(0, 0, 0, 0); s++; // #rgb // #rgba // #rrggbb // #rrggbbaa if (len == 4) { c.r = ParseHexCharSingle(s + 0); c.g = ParseHexCharSingle(s + 1); c.b = ParseHexCharSingle(s + 2); c.a = 255; //Trace( "color %s -> %d\n", s, (int) c.r ); } else if (len == 5) { c.r = ParseHexCharSingle(s + 0); c.g = ParseHexCharSingle(s + 1); c.b = ParseHexCharSingle(s + 2); c.a = ParseHexCharSingle(s + 3); } else if (len == 7) { c.r = ParseHexCharPair(s + 0); c.g = ParseHexCharPair(s + 2); c.b = ParseHexCharPair(s + 4); c.a = 255; } else if (len == 9) { c.r = ParseHexCharPair(s + 0); c.g = ParseHexCharPair(s + 2); c.b = ParseHexCharPair(s + 4); c.a = ParseHexCharPair(s + 6); } else { ParseFail("Parse failed, invalid color %.*s\n", (int) len, s); return false; } v = c; return true; }
bool Size::Parse(const char* s, size_t len, Size& v) { // 1.23px // 1.23ep // 1.23pt // 1.23% // 0 char digits[100]; if (len > 30) { ParseFail("Parse failed, size too big (>30 characters)\n"); return false; } Size x = Size::Pixels(0); size_t nondig = 0; for (; nondig < len; nondig++) { digits[nondig] = s[nondig]; if (!IsNumeric(s[nondig])) break; } digits[nondig] = 0; x.Val = (float) atof(digits); if (nondig == len) { if (len == 1 && s[0] == '0') { // ok } else { ParseFail("Parse failed, invalid size: %.*s\n", (int) len, s); return false; } } else { if (s[nondig] == '%') { x.Type = Size::PERCENT; } else if (s[nondig] == 'p' && len - nondig >= 2) { if (s[nondig + 1] == 'x') x.Type = Size::PX; else if (s[nondig + 1] == 't') x.Type = Size::PT; else { ParseFail("Parse failed, invalid size: %.*s\n", (int) len, s); return false; } } else if (s[nondig] == 'e' && len - nondig >= 2 && s[nondig + 1] == 'p') { x.Type = Size::EP; } } v = x; return true; }
static bool ParseDirect(const char* s, size_t len, bool (*parseFunc)(const char* s, size_t len, Style& style), Style& style) { if (parseFunc(s, len, style)) { return true; } else { ParseFail("Parse failed on: '%.*s'\n", (int) len, s); return false; } }
static bool ParseCompound(const char* s, size_t len, bool (*parseFunc)(const char* s, size_t len, T& t), StyleCategories cat, Style& style) { T val; if (parseFunc(s, len, val)) { style.Set(cat, val); return true; } else { ParseFail("Parse failed, unknown value: '%.*s'\n", (int) len, s); return false; } }
static bool ParseBool(const char* s, size_t len, StyleCategories cat, Style& style) { bool val; if (len == 4 && s[0] == 't') val = true; else if (len == 5 && s[0] == 'f') val = false; else { ParseFail("Parse failed, illegal boolean value: '%.*s'. Valid values are 'true' and 'false'.\n", (int) len, s); return false; } StyleAttrib attrib; attrib.SetBool(cat, val); style.Set(attrib); return true; }
bool DomNode::StyleParsef(const char* t, ...) { char buff[8192]; va_list va; va_start(va, t); uint32_t r = vsnprintf(buff, arraysize(buff), t, va); va_end(va); buff[arraysize(buff) - 1] = 0; if (r < arraysize(buff)) { return StyleParse(buff); } else { String str = String(t); str.Z[50] = 0; ParseFail("Parse string is too long for StyleParsef: %s...", str.Z); XO_DEBUG_ASSERT(false); return false; } }
bool Style::Parse(const char* t, size_t maxLen, Doc* doc) { // "background: #8f8; width: 100%; height: 100%;" #define TSTART (t + startv) #define TLEN (i - startv) size_t startk = -1; size_t eq = -1; size_t startv = -1; int nerror = 0; for (size_t i = 0; true; i++) { bool eof = t[i] == 0 || i == maxLen; if (t[i] == 32) { } else if (t[i] == ':') eq = i; else if (t[i] == ';' || (eof && startv != -1)) { // clang-format off bool ok = true; if (MATCH(t, startk, eq, "background")) { ok = ParseSingleAttrib(TSTART, TLEN, &Color::Parse, CatBackground, *this); } else if (MATCH(t, startk, eq, "color")) { ok = ParseSingleAttrib(TSTART, TLEN, &Color::Parse, CatColor, *this); } else if (MATCH(t, startk, eq, "width")) { ok = ParseSingleAttrib(TSTART, TLEN, &Size::Parse, CatWidth, *this); } else if (MATCH(t, startk, eq, "height")) { ok = ParseSingleAttrib(TSTART, TLEN, &Size::Parse, CatHeight, *this); } else if (MATCH(t, startk, eq, "padding")) { ok = ParseCompound(TSTART, TLEN, &StyleBox::Parse, CatPadding_Left, *this); } else if (MATCH(t, startk, eq, "margin")) { ok = ParseCompound(TSTART, TLEN, &StyleBox::Parse, CatMargin_Left, *this); } else if (MATCH(t, startk, eq, "display")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseDisplayType, CatDisplay, *this); } else if (MATCH(t, startk, eq, "position")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParsePositionType, CatPosition, *this); } else if (MATCH(t, startk, eq, "border")) { ok = ParseDirect(TSTART, TLEN, &ParseBorder, *this); } else if (MATCH(t, startk, eq, "border-radius")) { ok = ParseSingleAttrib(TSTART, TLEN, &Size::Parse, CatBorderRadius, *this); } //else if ( MATCH(t, startk, eq, "left") ) { ok = ParseSingleAttrib( TSTART, TLEN, &Size::Parse, CatLeft, *this ); } //else if ( MATCH(t, startk, eq, "right") ) { ok = ParseSingleAttrib( TSTART, TLEN, &Size::Parse, CatRight, *this ); } //else if ( MATCH(t, startk, eq, "top") ) { ok = ParseSingleAttrib( TSTART, TLEN, &Size::Parse, CatTop, *this ); } //else if ( MATCH(t, startk, eq, "bottom") ) { ok = ParseSingleAttrib( TSTART, TLEN, &Size::Parse, CatBottom, *this ); } else if (MATCH(t, startk, eq, "break")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseBreakType, CatBreak, *this); } else if (MATCH(t, startk, eq, "canfocus")) { ok = ParseBool(TSTART, TLEN, CatCanFocus, *this); } else if (MATCH(t, startk, eq, "cursor")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseCursor, CatCursor, *this); } else if (MATCH(t, startk, eq, "flow-context")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseFlowContext, CatFlowContext, *this); } else if (MATCH(t, startk, eq, "flow-axis")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseFlowAxis, CatFlowAxis, *this); } else if (MATCH(t, startk, eq, "flow-direction-horizontal")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseFlowDirection, CatFlowDirection_Horizontal, *this); } else if (MATCH(t, startk, eq, "flow-direction-vertical")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseFlowDirection, CatFlowDirection_Vertical, *this); } else if (MATCH(t, startk, eq, "box-sizing")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseBoxSize, CatBoxSizing, *this); } else if (MATCH(t, startk, eq, "font-size")) { ok = ParseSingleAttrib(TSTART, TLEN, &Size::Parse, CatFontSize, *this); } else if (MATCH(t, startk, eq, "font-family")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseFontFamily, CatFontFamily, *this); } else if (MATCH(t, startk, eq, "text-align-vertical")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseTextAlignVertical, CatText_Align_Vertical, *this); } else if (MATCH(t, startk, eq, "left")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseHorizontalBinding, CatLeft, *this); } else if (MATCH(t, startk, eq, "hcenter")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseHorizontalBinding, CatHCenter, *this); } else if (MATCH(t, startk, eq, "right")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseHorizontalBinding, CatRight, *this); } else if (MATCH(t, startk, eq, "top")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseVerticalBinding, CatTop, *this); } else if (MATCH(t, startk, eq, "vcenter")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseVerticalBinding, CatVCenter, *this); } else if (MATCH(t, startk, eq, "bottom")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseVerticalBinding, CatBottom, *this); } else if (MATCH(t, startk, eq, "baseline")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseVerticalBinding, CatBaseline, *this); } else if (MATCH(t, startk, eq, "bump")) { ok = ParseSingleAttrib(TSTART, TLEN, &ParseBump, CatBump, *this); } // clang-format on else { ok = false; ParseFail("Parse failed - unknown property: '%.*s'\n", int(eq - startk), t + startk); } if (!ok) nerror++; eq = -1; startk = -1; startv = -1; } else { if (startk == -1) startk = i; else if (startv == -1 && eq != -1) startv = i; } if (eof) break; } return nerror == 0; #undef TSTART #undef TLEN }