From 4f49b16079b27d7ce633619e4cddfdf2bffbc952 Mon Sep 17 00:00:00 2001 From: cashmere Date: Fri, 4 Sep 2026 09:05:24 +0200 Subject: initial commit --- src/color.c | 542 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 542 insertions(+) create mode 100644 src/color.c (limited to 'src/color.c') diff --git a/src/color.c b/src/color.c new file mode 100644 index 0000000..c89ffc7 --- /dev/null +++ b/src/color.c @@ -0,0 +1,542 @@ +/* +** Copyright (c) 2007 D. Richard Hipp +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the Simplified BSD License (also +** known as the "2-Clause License" or "FreeBSD License".) + +** This program 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. +** +** Author contact information: +** drh@hwaci.com +** http://www.hwaci.com/drh/ +** +******************************************************************************* +** +** This file contains code used to select colors based on branch and +** user names. +** +*/ +#include "config.h" +#include +#include "color.h" + +/* +** 140 standard CSS color names and their corresponding RGB values, +** in alphabetical order by name so that we can do a binary search +** for lookup. +*/ +static const struct CssColors { + const char *zName; /* CSS Color name, lower case */ + unsigned int iRGB; /* Corresponding RGB value */ +} aCssColors[] = { + { "aliceblue", 0xf0f8ff }, + { "antiquewhite", 0xfaebd7 }, + { "aqua", 0x00ffff }, + { "aquamarine", 0x7fffd4 }, + { "azure", 0xf0ffff }, + { "beige", 0xf5f5dc }, + { "bisque", 0xffe4c4 }, + { "black", 0x000000 }, + { "blanchedalmond", 0xffebcd }, + { "blue", 0x0000ff }, + { "blueviolet", 0x8a2be2 }, + { "brown", 0xa52a2a }, + { "burlywood", 0xdeb887 }, + { "cadetblue", 0x5f9ea0 }, + { "chartreuse", 0x7fff00 }, + { "chocolate", 0xd2691e }, + { "coral", 0xff7f50 }, + { "cornflowerblue", 0x6495ed }, + { "cornsilk", 0xfff8dc }, + { "crimson", 0xdc143c }, + { "cyan", 0x00ffff }, + { "darkblue", 0x00008b }, + { "darkcyan", 0x008b8b }, + { "darkgoldenrod", 0xb8860b }, + { "darkgray", 0xa9a9a9 }, + { "darkgreen", 0x006400 }, + { "darkkhaki", 0xbdb76b }, + { "darkmagenta", 0x8b008b }, + { "darkolivegreen", 0x556b2f }, + { "darkorange", 0xff8c00 }, + { "darkorchid", 0x9932cc }, + { "darkred", 0x8b0000 }, + { "darksalmon", 0xe9967a }, + { "darkseagreen", 0x8fbc8f }, + { "darkslateblue", 0x483d8b }, + { "darkslategray", 0x2f4f4f }, + { "darkturquoise", 0x00ced1 }, + { "darkviolet", 0x9400d3 }, + { "deeppink", 0xff1493 }, + { "deepskyblue", 0x00bfff }, + { "dimgray", 0x696969 }, + { "dodgerblue", 0x1e90ff }, + { "firebrick", 0xb22222 }, + { "floralwhite", 0xfffaf0 }, + { "forestgreen", 0x228b22 }, + { "fuchsia", 0xff00ff }, + { "gainsboro", 0xdcdcdc }, + { "ghostwhite", 0xf8f8ff }, + { "gold", 0xffd700 }, + { "goldenrod", 0xdaa520 }, + { "gray", 0x808080 }, + { "green", 0x008000 }, + { "greenyellow", 0xadff2f }, + { "honeydew", 0xf0fff0 }, + { "hotpink", 0xff69b4 }, + { "indianred", 0xcd5c5c }, + { "indigo", 0x4b0082 }, + { "ivory", 0xfffff0 }, + { "khaki", 0xf0e68c }, + { "lavender", 0xe6e6fa }, + { "lavenderblush", 0xfff0f5 }, + { "lawngreen", 0x7cfc00 }, + { "lemonchiffon", 0xfffacd }, + { "lightblue", 0xadd8e6 }, + { "lightcoral", 0xf08080 }, + { "lightcyan", 0xe0ffff }, + { "lightgoldenrodyellow", 0xfafad2 }, + { "lightgrey", 0xd3d3d3 }, + { "lightgreen", 0x90ee90 }, + { "lightpink", 0xffb6c1 }, + { "lightsalmon", 0xffa07a }, + { "lightseagreen", 0x20b2aa }, + { "lightskyblue", 0x87cefa }, + { "lightslategray", 0x778899 }, + { "lightsteelblue", 0xb0c4de }, + { "lightyellow", 0xffffe0 }, + { "lime", 0x00ff00 }, + { "limegreen", 0x32cd32 }, + { "linen", 0xfaf0e6 }, + { "magenta", 0xff00ff }, + { "maroon", 0x800000 }, + { "mediumaquamarine", 0x66cdaa }, + { "mediumblue", 0x0000cd }, + { "mediumorchid", 0xba55d3 }, + { "mediumpurple", 0x9370d8 }, + { "mediumseagreen", 0x3cb371 }, + { "mediumslateblue", 0x7b68ee }, + { "mediumspringgreen", 0x00fa9a }, + { "mediumturquoise", 0x48d1cc }, + { "mediumvioletred", 0xc71585 }, + { "midnightblue", 0x191970 }, + { "mintcream", 0xf5fffa }, + { "mistyrose", 0xffe4e1 }, + { "moccasin", 0xffe4b5 }, + { "navajowhite", 0xffdead }, + { "navy", 0x000080 }, + { "oldlace", 0xfdf5e6 }, + { "olive", 0x808000 }, + { "olivedrab", 0x6b8e23 }, + { "orange", 0xffa500 }, + { "orangered", 0xff4500 }, + { "orchid", 0xda70d6 }, + { "palegoldenrod", 0xeee8aa }, + { "palegreen", 0x98fb98 }, + { "paleturquoise", 0xafeeee }, + { "palevioletred", 0xd87093 }, + { "papayawhip", 0xffefd5 }, + { "peachpuff", 0xffdab9 }, + { "peru", 0xcd853f }, + { "pink", 0xffc0cb }, + { "plum", 0xdda0dd }, + { "powderblue", 0xb0e0e6 }, + { "purple", 0x800080 }, + { "red", 0xff0000 }, + { "rosybrown", 0xbc8f8f }, + { "royalblue", 0x4169e1 }, + { "saddlebrown", 0x8b4513 }, + { "salmon", 0xfa8072 }, + { "sandybrown", 0xf4a460 }, + { "seagreen", 0x2e8b57 }, + { "seashell", 0xfff5ee }, + { "sienna", 0xa0522d }, + { "silver", 0xc0c0c0 }, + { "skyblue", 0x87ceeb }, + { "slateblue", 0x6a5acd }, + { "slategray", 0x708090 }, + { "snow", 0xfffafa }, + { "springgreen", 0x00ff7f }, + { "steelblue", 0x4682b4 }, + { "tan", 0xd2b48c }, + { "teal", 0x008080 }, + { "thistle", 0xd8bfd8 }, + { "tomato", 0xff6347 }, + { "turquoise", 0x40e0d0 }, + { "violet", 0xee82ee }, + { "wheat", 0xf5deb3 }, + { "white", 0xffffff }, + { "whitesmoke", 0xf5f5f5 }, + { "yellow", 0xffff00 }, + { "yellowgreen", 0x9acd32 }, +}; + +/* +** Attempt to translate a CSS color name into an integer that +** represents the equivalent RGB value. Ignore alpha if provided. +** If the name cannot be translated, return -1. +*/ +int color_name_to_rgb(const char *zName){ + if( zName==0 || zName[0]==0 ) return -1; + if( zName[0]=='#' ){ + int i, v = 0; + for(i=1; i<=6 && fossil_isxdigit(zName[i]); i++){ + v = v*16 + fossil_hexvalue(zName[i]); + } + if( i==4 ){ + v = fossil_hexvalue(zName[1])*0x110000 + + fossil_hexvalue(zName[2])*0x1100 + + fossil_hexvalue(zName[3])*0x11; + return v; + } + if( i==7 ){ + return v; + } + return -1; + }else{ + int iMin = 0; + int iMax = count(aCssColors)-1; + while( iMin<=iMax ){ + int iMid = (iMin+iMax)/2; + int c = sqlite3_stricmp(aCssColors[iMid].zName, zName); + if( c==0 ) return aCssColors[iMid].iRGB; + if( c<0 ){ + iMin = iMid+1; + }else{ + iMax = iMid-1; + } + } + return -1; + } +} + +/* +** SETTING: raw-bgcolor boolean default=off +** +** Fossil usually tries to adjust user-specified background colors +** for check-ins so that the text is readable and so that the color +** is not too garish. This setting disables that filter. When +** this setting is on, the user-selected background colors are shown +** exactly as requested. +*/ + +/* +** Shift a color provided by the user so that it is suitable +** for use as a background color in the current skin. +** +** The return value is a #HHHHHH color name contained in +** static space that is overwritten on the next call. +** +** If we cannot make sense of the background color recommendation +** that is the input, then return NULL. +** +** The iFgClr parameter is normally 0. But for testing purposes, set +** it to 1 for a black foregrounds and 2 for a white foreground. +*/ +const char *reasonable_bg_color(const char *zRequested, int iFgClr){ + int iRGB = color_name_to_rgb(zRequested); + int r, g, b; /* RGB components of requested color */ + static int systemFg = 0; /* 1==black-foreground 2==white-foreground */ + int fg; /* Foreground color to actually use */ + static char zColor[10]; /* Return value */ + + if( iFgClr ){ + fg = iFgClr; + }else if( systemFg==0 ){ + if( db_get_boolean("raw-bgcolor",0) ){ + fg = systemFg = 3; + }else{ + fg = systemFg = skin_detail_boolean("white-foreground") ? 2 : 1; + } + }else{ + fg = systemFg; + } + if( fg>=3 ) return zRequested; + + if( iRGB<0 ) return 0; + r = (iRGB>>16) & 0xff; + g = (iRGB>>8) & 0xff; + b = iRGB & 0xff; + if( fg==1 ){ + /* Dark text on a light background. Adjust so that + ** no color component is less than 255-K, resulting in + ** a pastel background color. Color adjustment is quadratic + ** so that colors that are further out of range have a greater + ** adjustment. */ + const int K = 79; + int k, x, m; + m = rb ) m = b; + k = (m*m)/255 + K; + x = 255 - k; + r = (k*r)/255 + x; + g = (k*g)/255 + x; + b = (k*b)/255 + x; + }else{ + /* Light text on a dark background. Adjust so that + ** no color component is greater than K, resulting in + ** a low-intensity, low-saturation background color. + ** The color adjustment is quadratic so that colors that + ** are further out of range have a greater adjustment. */ + const int K = 112; + int k, m; + m = r>g ? r : g; + if( m>3) ^ z[i]; + } + return h; +} + +/* +** Hash a string and use the hash to determine a background color. +** +** This value returned is in static space and is overwritten with +** each subsequent call. +*/ +char *hash_color(const char *z){ + unsigned int h = 0; /* Hash on the branch name */ + int r, g, b; /* Values for red, green, and blue */ + int h1, h2, h3, h4; /* Elements of the hash value */ + int mx, mn; /* Components of HSV */ + static char zColor[10]; /* The resulting color */ + static int ix[3] = {0,0}; /* Color chooser parameters */ + + if( ix[0]==0 ){ + if( skin_detail_boolean("white-foreground") ){ + ix[0] = 0x50; + ix[1] = 0x20; + }else{ + ix[0] = 0xf8; + ix[1] = 0x20; + } + } + h = hash_of_name(z); + h1 = h % 6; h /= 6; + h3 = h % 10; h /= 10; + h4 = h % 10; h /= 10; + mx = ix[0] - h3; + mn = mx - h4 - ix[1]; + h2 = (h%(mx - mn)) + mn; + switch( h1 ){ + case 0: r = mx; g = h2, b = mn; break; + case 1: r = h2; g = mx, b = mn; break; + case 2: r = mn; g = mx, b = h2; break; + case 3: r = mn; g = h2, b = mx; break; + case 4: r = h2; g = mn, b = mx; break; + default: r = mx; g = mn, b = h2; break; + } + sqlite3_snprintf(8, zColor, "#%02x%02x%02x", r,g,b); + return zColor; +} + +/* +** Determine a color for users based on their login string. +** +** SETTING: user-color-map width=40 block-text +** +** The user-color-map setting can be used to override user color choices. +** The setting is a list of space-separated words pairs. The first word +** of each pair is a login name. The second word is an alternative name +** used by the color chooser algorithm. +** +** This list is intended to be relatively short. The idea is to only use +** this map to resolve color collisions between common users. +** +** Visit /hash-color-test?rand for a list of suggested names for the +** second word of each pair in the list. +*/ +char *user_color(const char *zLogin){ + static int once = 0; + static int nMap = 0; + static char **azMap = 0; + static int *anMap = 0; + int i; + if( !once ){ + char *zMap = (char*)db_get("user-color-map",0); + once = 1; + if( zMap && zMap[0] ){ + if( !g.interp ) Th_FossilInit(0); + Th_SplitList(g.interp, zMap, (int)strlen(zMap), + &azMap, &anMap, &nMap); + for(i=0; i + @ %h(zBr) - hash 0x%x(hash_of_name(zBr)) - color %s(hash_color(zBr)) - + @ Omnes nos quasi oves erravimus unusquisque in viam + @ suam declinavit.

+ cnt++; + } + } + if( cnt ){ + @
+ } + @
+ @

Enter candidate branch names below and see them displayed in their + @ default background colors above.

+ for(i=0; i<10; i++){ + sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i); + zBr = P(zNm); + @
+ } + @ + @ + @
+ style_finish_page(); +} + +/* +** WEBPAGE: test-bgcolor +** +** Show how user-specified background colors will be rendered +** using the reasonable_bg_color() algorithm. +*/ +void test_bgcolor_page(void){ + const char *zReq; /* Requested color name */ + const char *zBG; /* Actual color provided */ + const char *zBg1; + char zNm[10]; + static const char *azDflt[] = { + "red", "orange", "yellow", "green", "blue", "indigo", "violet", + "tan", "brown", "gray", + }; + const int N = count(azDflt); + int i, cnt, iClr, r, g, b; + char *zFg; + login_check_credentials(); + style_set_current_feature("test"); + style_header("Background Color Test"); + for(i=cnt=0; i + @ + @ Requested Background + @ Light mode + @ Dark mode + @ + } + cnt++; + zBG = reasonable_bg_color(zReq, 0); + if( zBG==0 ){ + @ \ + @ "%h(zReq)" is not a recognized color name + continue; + } + iClr = color_name_to_rgb(zReq); + r = (iClr>>16) & 0xff; + g = (iClr>>8) & 0xff; + b = iClr & 0xff; + if( 3*r + 7*g + b > 6*255 ){ + zFg = "black"; + }else{ + zFg = "white"; + } + if( zReq[0]!='#' ){ + char zReqRGB[12]; + sqlite3_snprintf(sizeof(zReqRGB),zReqRGB,"#%06x",color_name_to_rgb(zReq)); + @ \ + @ Requested color "%h(zReq)" (%h(zReqRGB)) + }else{ + @ \ + @ Requested color "%h(zReq)" + } + zBg1 = reasonable_bg_color(zReq,1); + @ \ + @ Background color for dark text: %h(zBg1) + zBg1 = reasonable_bg_color(zReq,2); + @ \ + @ Background color for light text: %h(zBg1) + } + if( cnt ){ + @ + @
+ } + @
+ @

Enter CSS color names below and see them shifted into corresponding + @ background colors above.

+ for(i=0; i
+ } + @ + @ + style_finish_page(); +} -- cgit v1.3.1