home
readme
diff
tree
note
docs
0commit 8afb721e13a9f37189a21eccccc943ad68d081dc
1Author: lakefox <mason@lakefox.net>
2Date: Thu Jan 1 11:35:15 2026 -0700
3
4 ClassList/StyleList Update: See Note
5
6diff --git a/include/grim.h b/include/grim.h
7index 9496863..e7ef8c6 100755
8--- a/include/grim.h
9+++ b/include/grim.h
10@@ -121,61 +121,71 @@ struct Unit {
11
12 class Window;
13
14+struct ClassList {
15+ private:
16+ std::string* classString;
17+ std::vector<std::pair<int, int>> indexes;
18+ size_t len;
19+ // No return, modifies indexes directly
20+ void createIndex();
21+ bool checkIndex();
22+
23+ public:
24+ ClassList(std::string* cs) : classString(cs) {}
25+ void add(std::string value);
26+ void remove(std::string value);
27+ void toggle(std::string value);
28+ void replace(std::string key, std::string value);
29+ bool contains(std::string value);
30+ std::string item(size_t key);
31+ size_t length();
32+};
33+
34+struct StyleList {
35+ private:
36+ std::string* styleString;
37+ std::vector<std::tuple<int, int, int>> indexes;
38+ size_t len;
39+ void createIndex();
40+ bool checkIndex();
41+ public:
42+ StyleList(std::string* sS) : styleString(sS) {}
43+ std::string get(std::string key);
44+ std::vector<Unit> getUnit(std::string key);
45+ void set(std::string key, std::string value);
46+ void remove(std::string key);
47+ std::pair<std::string, std::string> item(size_t index);
48+ size_t length();
49+};
50+
51 class Node {
52 private:
53- std::string TagName;
54+ std::string TagName = "";
55 std::unordered_map<std::string, std::string> attributes;
56+ float em = 0;
57+ float width = 0;
58+ float height = 0;
59 public:
60 Window* window;
61
62 Node* parent;
63+
64 std::vector<Node> children;
65- struct ClassList {
66- private:
67- Node* self;
68- std::vector<std::pair<int, int>> indexes;
69- size_t len;
70- // No return, modifies indexes directly
71- void createIndex();
72- bool checkIndex();
73-
74- public:
75- ClassList(Node* node) : self(node) {}
76- void add(std::string value);
77- void remove(std::string value);
78- void toggle(std::string value);
79- void replace(std::string key, std::string value);
80- bool contains(std::string value);
81- std::string item(size_t key);
82- size_t length();
83- };
84+ ClassList classList() { return ClassList(&this->attributes["class"]); }
85+ StyleList style() { return StyleList(&this->attributes["style"]); }
86
87- ClassList classList;
88-
89- struct StyleList {
90- private:
91- Node* self;
92- std::vector<std::tuple<int, int, int>> indexes;
93- size_t len;
94- void createIndex();
95- bool checkIndex();
96- public:
97- StyleList(Node* node) : self(node) {}
98- std::string get(std::string key);
99- std::vector<Unit> getUnit(std::string key);
100- void set(std::string key, std::string value);
101- void remove(std::string key);
102- std::pair<std::string, std::string> item(size_t index);
103- size_t length();
104- };
105-
106- StyleList style;
107-
108- Node() : parent(nullptr), classList(this), style(this) {}
109+ Node() : parent(nullptr) {}
110
111 std::string getTagName() const;
112 void setTagName(const std::string& name);
113
114+ float getEM() const; // Returns value from the cache
115+ float getWidth() const;
116+ float getHeight() const;
117+ void cacheEM(const float value); // Sets the cache value (should not be manually used)
118+ void cacheWidth(const float value);
119+ void cacheHeight(const float value);
120+
121 Node* createElement(std::string name);
122
123 void setAttribute(const std::string& name, const std::string& value);
124diff --git a/src/grim.cc b/src/grim.cc
125index 6cde02b..1dcbc67 100755
126--- a/src/grim.cc
127+++ b/src/grim.cc
128@@ -103,7 +103,9 @@ static const std::unordered_map<std::string, std::string> DEFAULT_ATTRIBUTE_VALU
129 };
130
131 // Tag Name is not a attribute so it needs to be handled differently
132-std::string Node::getTagName() const { return TagName; }
133+std::string Node::getTagName() const {
134+ return TagName;
135+}
136 void Node::setTagName(const std::string& name) { TagName = name; }
137
138 void Node::setAttribute(const std::string& name, const std::string& value) {
139@@ -145,15 +147,45 @@ const std::unordered_map<std::string, std::string>& Node::getAttributes() const
140 return attributes;
141 }
142
143+// +---------------------------------------------------+
144+// | (o78ty) Cache |
145+// +---------------------------------------------------+
146+// For frequently accessed values like em, width, height
147+// it makes sense to not fully calculate the value access
148+// during rendering as it is very intensive. The functions
149+// below are used to store/retrive the last calculated
150+// value. cache*() will not set the real value for the
151+// Nodei, it only effects the interval variables.
152+
153+float Node::getEM() const {
154+ return em;
155+}
156+float Node::getWidth() const {
157+ return width;
158+}
159+float Node::getHeight() const {
160+ return height;
161+}
162+void Node::cacheEM(const float value) {
163+ em = value;
164+}
165+void Node::cacheWidth(const float value) {
166+ width = value;
167+}
168+void Node::cacheHeight(const float value) {
169+ height = value;
170+}
171+
172+
173 // +---------------------------------------------------+
174 // | (f98y0) ClassList |
175 // +---------------------------------------------------+
176
177-void Node::ClassList::createIndex() {
178+void ClassList::createIndex() {
179 int index = 0;
180 // Add a space to the back to help trigger the adding of the
181 // last item
182- std::string classes = self->attributes["class"]+" ";
183+ std::string classes = *classString+" ";
184 // Update the stored length
185 len = classes.length();
186 indexes.clear();
187@@ -174,9 +206,8 @@ void Node::ClassList::createIndex() {
188 }
189
190
191-bool Node::ClassList::checkIndex() {
192- std::string classes = self->attributes["class"];
193- if (classes.length() != len) {
194+bool ClassList::checkIndex() {
195+ if (classString->length() != len) {
196 return false;
197 } else {
198 // Skip the first one because there is a space
199@@ -186,7 +217,7 @@ bool Node::ClassList::checkIndex() {
200 for (size_t i = 1; i < indexes.size(); i++) {
201 // See if the index position is a space
202 // if not return false
203- if (classes[indexes[i-1].first] != ' ') {
204+ if (!std::isspace(classString->at(indexes[i-1].first))) {
205 return false;
206 }
207 }
208@@ -194,7 +225,7 @@ bool Node::ClassList::checkIndex() {
209 }
210 }
211
212-size_t Node::ClassList::length() {
213+size_t ClassList::length() {
214 if (!checkIndex()) {
215 createIndex();
216 }
217@@ -202,27 +233,27 @@ size_t Node::ClassList::length() {
218 }
219
220
221-std::string Node::ClassList::item(size_t key) {
222+std::string ClassList::item(size_t key) {
223 if (!checkIndex()) {
224 createIndex();
225 }
226 if (key < indexes.size()) {
227 std::pair<int, int> pair = indexes[key];
228- return self->attributes["class"].substr(pair.first, pair.second);
229+ return classString->substr(pair.first, pair.second);
230 } else {
231 return "";
232 }
233 }
234
235-void Node::ClassList::add(std::string value) {
236+void ClassList::add(std::string value) {
237 if (!checkIndex()) {
238 createIndex();
239 }
240
241- if (self->attributes["class"].length() == 0) {
242- self->attributes["class"] += value;
243+ if (classString->length() == 0) {
244+ classString->append(value);
245 } else {
246- self->attributes["class"] += " "+value;
247+ classString->append(" "+value);
248 }
249 // len because the index of the added space will be the length of
250 // the prevous string
251@@ -231,42 +262,40 @@ void Node::ClassList::add(std::string value) {
252 len += vl+1;
253 }
254
255-void Node::ClassList::remove(std::string value) {
256+void ClassList::remove(std::string value) {
257 if (!checkIndex()) {
258 createIndex();
259 }
260
261 int newLen = value.length();
262 size_t cLen = indexes.size();
263- std::string classes = self->attributes["class"];
264
265 for (size_t i = 0; i < cLen; i++) {
266 std::pair<int, int> pair = indexes[i];
267 if (newLen == pair.second) {
268- if (classes.substr(pair.first, pair.second) == value) {
269+ if (classString->substr(pair.first, pair.second) == value) {
270 // Splice out the value to be removed
271 // ISSUE: This will keep the surounding spaces and cause the size to grow when
272 // classes are added and removed
273- self->attributes["class"] = classes.substr(0, pair.first)+classes.substr(pair.first+pair.second);
274+ classString->erase(pair.first, pair.second);
275 }
276 }
277 }
278 }
279
280-bool Node::ClassList::contains(std::string value) {
281+bool ClassList::contains(std::string value) {
282 if (!checkIndex()) {
283 createIndex();
284 }
285
286 int newLen = value.length();
287 size_t cLen = indexes.size();
288- std::string classes = self->attributes["class"];
289 bool found = false;
290
291 for (size_t i = 0; i < cLen; i++) {
292 std::pair<int, int> pair = indexes[i];
293 if (newLen == pair.second) {
294- if (classes.substr(pair.first, pair.second) == value) {
295+ if (classString->substr(pair.first, pair.second) == value) {
296 // Same logic as remove but turns found true then breaks
297 found = true;
298 break;
299@@ -276,7 +305,7 @@ bool Node::ClassList::contains(std::string value) {
300 return found;
301 }
302
303-void Node::ClassList::toggle(std::string value) {
304+void ClassList::toggle(std::string value) {
305 if (contains(value)) {
306 remove(value);
307 } else {
308@@ -302,10 +331,9 @@ void Node::ClassList::toggle(std::string value) {
309 // getUnit is a interal method to get styles from the stylelist
310 // as parsed units for rendering
311
312-void Node::StyleList::createIndex() {
313- std::string styles = self->attributes["style"];
314+void StyleList::createIndex() {
315 // Update the stored length
316- len = styles.length();
317+ len = styleString->length();
318 indexes.clear();
319
320 // " background-color: white;"
321@@ -327,7 +355,7 @@ void Node::StyleList::createIndex() {
322
323
324 for (size_t i = 0; i < len; i++) {
325- char s = styles[i];
326+ char s = styleString->at(i);
327 if (firstNonWhiteSpace) {
328 if (keyFound) {
329 if (secondNonWhiteSpace) {
330@@ -357,15 +385,14 @@ void Node::StyleList::createIndex() {
331 }
332
333
334-bool Node::StyleList::checkIndex() {
335- std::string styles = self->attributes["style"];
336- if (styles.length() != len) {
337+bool StyleList::checkIndex() {
338+ if (styleString->length() != len) {
339 return false;
340 } else {
341 for (size_t i = 0; i < indexes.size(); i++) {
342- if (std::isspace(styles[std::get<0>(indexes[i])]) ||
343- styles[std::get<1>(indexes[i])] != ':' ||
344- styles[std::get<2>(indexes[i])] != ';'
345+ if (std::isspace(styleString->at(std::get<0>(indexes[i]))) ||
346+ styleString->at(std::get<1>(indexes[i])) != ':' ||
347+ styleString->at(std::get<2>(indexes[i])) != ';'
348 ) {
349 return false;
350 }
351@@ -374,46 +401,44 @@ bool Node::StyleList::checkIndex() {
352 }
353 }
354
355-std::pair<std::string, std::string> Node::StyleList::item(size_t index) {
356+std::pair<std::string, std::string> StyleList::item(size_t index) {
357 if (!checkIndex()) {
358 createIndex();
359 }
360
361 std::pair<std::string, std::string> property;
362- std::string styles = self->attributes["style"];
363
364 int f = std::get<0>(indexes[index]);
365 int s = std::get<1>(indexes[index]);
366- property.first = styles.substr(f, s-f);
367+ property.first = styleString->substr(f, s-f);
368 trimSpace(property.first);
369
370 int t = std::get<2>(indexes[index]);
371- property.second = styles.substr(s+1, t-(s+1));
372+ property.second = styleString->substr(s+1, t-(s+1));
373 trimSpace(property.second);
374 return property;
375
376 }
377
378-size_t Node::StyleList::length() {
379+size_t StyleList::length() {
380 if (!checkIndex()) {
381 createIndex();
382 }
383 return indexes.size();
384 }
385
386-std::string Node::StyleList::get(std::string key) {
387+std::string StyleList::get(std::string key) {
388 if (!checkIndex()) {
389 createIndex();
390 }
391- std::string styles = self->attributes["style"];
392 for (size_t i = 0; i < indexes.size(); i++) {
393 int f = std::get<0>(indexes[i]);
394 int s = std::get<1>(indexes[i]);
395- std::string slicedKey = styles.substr(f, s-f);
396+ std::string slicedKey = styleString->substr(f, s-f);
397 trimSpace(slicedKey);
398 if (slicedKey == key) {
399 int t = std::get<2>(indexes[i]);
400- std::string value = styles.substr(s+1, t-(s+1));
401+ std::string value = styleString->substr(s+1, t-(s+1));
402 trimSpace(value);
403 return value;
404 }
405@@ -421,19 +446,18 @@ std::string Node::StyleList::get(std::string key) {
406 return "";
407 }
408
409-std::vector<Unit> Node::StyleList::getUnit(std::string key) {
410+std::vector<Unit> StyleList::getUnit(std::string key) {
411 if (!checkIndex()) {
412 createIndex();
413 }
414- std::string styles = self->attributes["style"];
415 for (size_t i = 0; i < indexes.size(); i++) {
416 int f = std::get<0>(indexes[i]);
417 int s = std::get<1>(indexes[i]);
418- std::string slicedKey = styles.substr(f, s-f);
419+ std::string slicedKey = styleString->substr(f, s-f);
420 trimSpace(slicedKey);
421 if (slicedKey == key) {
422 int t = std::get<2>(indexes[i]);
423- std::string value = styles.substr(s+1, t-(s+1));
424+ std::string value = styleString->substr(s+1, t-(s+1));
425 trimSpace(value);
426 return getUnit(value);
427 }
428@@ -442,52 +466,53 @@ std::vector<Unit> Node::StyleList::getUnit(std::string key) {
429 return empty;
430 }
431
432-void Node::StyleList::set(std::string key, std::string value) {
433+void StyleList::set(std::string key, std::string value) {
434 if (!checkIndex()) {
435 createIndex();
436 }
437- std::string styles = self->attributes["style"];
438
439 for (size_t i = 0; i < indexes.size(); i++) {
440 int f = std::get<0>(indexes[i]);
441 int s = std::get<1>(indexes[i]);
442- std::string slicedKey = styles.substr(f, s-f);
443+
444+ std::string slicedKey = styleString->substr(f, s-f);
445 trimSpace(slicedKey);
446 if (slicedKey == key) {
447 int t = std::get<2>(indexes[i]);
448- self->attributes["style"] = styles.substr(0, f) +" "+key+":"+value+";"+styles.substr(t);
449+ styleString->replace(f,t-f," "+key+":"+value+";");
450 // Return early to skip the appending value;
451 return;
452 }
453 }
454
455 // If the property wasn't replaced then add it
456-
457- char lastChar = styles[std::get<2>(indexes[indexes.size()-1])];
458
459- if (lastChar == ';') {
460- self->attributes["style"] += " "+key+":"+value+";";
461- } else {
462- // If the user didn't terminate the last style
463- // terminate it for them
464- self->attributes["style"] += "; "+key+":"+value+";";
465+ if (!indexes.empty()) {
466+ char lastChar = styleString->at(std::get<2>(indexes[indexes.size()-1]));
467+
468+ if (lastChar == ';') {
469+ styleString->append(" "+key+":"+value+";");
470+ } else {
471+ // If the user didn't terminate the last style
472+ // terminate it for them
473+ styleString->append("; "+key+":"+value+";");
474+ }
475 }
476 }
477
478-void Node::StyleList::remove(std::string key) {
479+void StyleList::remove(std::string key) {
480 if (!checkIndex()) {
481 createIndex();
482 }
483- std::string styles = self->attributes["style"];
484
485 for (size_t i = 0; i < indexes.size(); i++) {
486 int f = std::get<0>(indexes[i]);
487 int s = std::get<1>(indexes[i]);
488- std::string slicedKey = styles.substr(f, s-f);
489+ std::string slicedKey = styleString->substr(f, s-f);
490 trimSpace(slicedKey);
491 if (slicedKey == key) {
492 int t = std::get<2>(indexes[i]);
493- self->attributes["style"] = styles.substr(0, f) + styles.substr(t);
494+ styleString->erase(f, t);
495 return;
496 }
497 }
498@@ -713,10 +738,12 @@ std::vector<std::string> parseNodeParts(Node* node) {
499 }
500 }
501
502- auto classLen = node->classList.length();
503+ ClassList cl = node->classList();
504+
505+ size_t classLen = cl.length();
506
507 for (size_t i = 0; i < classLen; i++) {
508- parts.push_back("."+node->classList.item(i));
509+ parts.push_back("."+cl.item(i));
510 }
511
512 parts.push_back("*");
513@@ -1208,12 +1235,7 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
514 // return at the earliest possible part avoiding unnessisary
515 // computing
516
517- std::vector<std::string> nodeClasses;
518- size_t classLen = node->classList.length();
519- for (size_t i = 0; i < classLen; i++) {
520- nodeClasses.push_back(node->classList.item(i));
521- }
522-
523+ ClassList cl = node->classList();
524
525 std::unordered_map<std::string, std::string> attributes = node->getAttributes();
526 std::vector<std::string> attrs;
527@@ -1318,12 +1340,8 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
528 } else if (p[0] == '.') {
529 bool found = false;
530 p.erase(0,1);
531- for (auto c : nodeClasses) {
532- if (p == c) {
533- found = true;
534- break;
535- }
536- }
537+ found = cl.contains(p);
538+
539 matched = found;
540 } else if (p[0] == '[') {
541 // This covers all attributes and non relative pseudo-classes
542@@ -1499,9 +1517,6 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
543
544 std::string pattern = parts[i+1].substr(1,parts[i+1].length()-2);
545
546- std::cout << "################################" << std::endl;
547- std::cout << pattern << std::endl;
548-
549 for (size_t i = 0; i < pattern.length(); i++) {
550 if (!std::isspace(pattern[i])) {
551 if (pattern[i] == '-' && !negFound) {
552@@ -1590,7 +1605,6 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
553 index = childIndex;
554 }
555 } else {
556- std::cout << "Has of: " << ofSelector << std::endl;
557 // Parse the of selector
558 auto pOS = parseSelectorParts(ofSelector.substr(2));
559 if (testSelector(node, pOS)) {
560@@ -1647,11 +1661,6 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
561 A = 1;
562 }
563
564- std::cout << "A: " << A << std::endl;
565- std::cout << "B: " << B << std::endl;
566- std::cout << "Sym: " << symbol << std::endl;
567- std::cout << "OF: " << ofSelector << std::endl;
568- std::cout << "Index: " << index << std::endl;
569
570 if (isBool) {
571 if (isEven) {