File indexing completed on 2024-12-08 12:19:29
0001 /* 0002 * This file is part of the CSS implementation for KDE. 0003 * 0004 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) 0005 * (C) David Carson <dacarson@gmail.com> 0006 * 0007 * This library is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU Library General Public 0009 * License as published by the Free Software Foundation; either 0010 * version 2 of the License, or (at your option) any later version. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Library General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Library General Public License 0018 * along with this library; see the file COPYING.LIB. If not, write to 0019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 * 0022 */ 0023 #include "helper.h" 0024 #include "khtmllayout.h" 0025 #include <QMap> 0026 #include <QPainter> 0027 #include <dom/dom_string.h> 0028 #include <xml/dom_stringimpl.h> 0029 #include <rendering/render_object.h> 0030 #include <kconfig.h> 0031 #include <kcolorscheme.h> 0032 #include <ksharedconfig.h> 0033 #include <kconfiggroup.h> 0034 #include <QToolTip> 0035 #include "css/cssvalues.h" 0036 0037 using namespace DOM; 0038 using namespace khtml; 0039 0040 namespace khtml 0041 { 0042 0043 QPainter *printpainter; 0044 0045 void setPrintPainter(QPainter *printer) 0046 { 0047 printpainter = printer; 0048 } 0049 0050 void findWordBoundary(QChar *chars, int len, int position, int *start, int *end) 0051 { 0052 if (chars[position].isSpace()) { 0053 int pos = position; 0054 while (pos >= 0 && chars[pos].isSpace()) { 0055 pos--; 0056 } 0057 *start = pos + 1; 0058 pos = position; 0059 while (pos < (int)len && chars[pos].isSpace()) { 0060 pos++; 0061 } 0062 *end = pos; 0063 } else if (chars[position].isPunct()) { 0064 int pos = position; 0065 while (pos >= 0 && chars[pos].isPunct()) { 0066 pos--; 0067 } 0068 *start = pos + 1; 0069 pos = position; 0070 while (pos < (int)len && chars[pos].isPunct()) { 0071 pos++; 0072 } 0073 *end = pos; 0074 } else { 0075 int pos = position; 0076 while (pos >= 0 && !chars[pos].isSpace() && !chars[pos].isPunct()) { 0077 pos--; 0078 } 0079 *start = pos + 1; 0080 pos = position; 0081 while (pos < (int)len && !chars[pos].isSpace() && !chars[pos].isPunct()) { 0082 pos++; 0083 } 0084 *end = pos; 0085 } 0086 } 0087 0088 } 0089 0090 // color mapping code 0091 struct colorMap { 0092 int css_value; 0093 QRgb color; 0094 }; 0095 0096 static const colorMap cmap[] = { 0097 { CSS_VAL_AQUA, 0xFF00FFFF }, 0098 { CSS_VAL_BLACK, 0xFF000000 }, 0099 { CSS_VAL_BLUE, 0xFF0000FF }, 0100 { CSS_VAL_CRIMSON, 0xFFDC143C }, 0101 { CSS_VAL_FUCHSIA, 0xFFFF00FF }, 0102 { CSS_VAL_GRAY, 0xFF808080 }, 0103 { CSS_VAL_GREEN, 0xFF008000 }, 0104 { CSS_VAL_INDIGO, 0xFF4B0082 }, 0105 { CSS_VAL_LIME, 0xFF00FF00 }, 0106 { CSS_VAL_MAROON, 0xFF800000 }, 0107 { CSS_VAL_NAVY, 0xFF000080 }, 0108 { CSS_VAL_OLIVE, 0xFF808000 }, 0109 { CSS_VAL_ORANGE, 0xFFFFA500 }, 0110 { CSS_VAL_PURPLE, 0xFF800080 }, 0111 { CSS_VAL_RED, 0xFFFF0000 }, 0112 { CSS_VAL_SILVER, 0xFFC0C0C0 }, 0113 { CSS_VAL_TEAL, 0xFF008080 }, 0114 { CSS_VAL_WHITE, 0xFFFFFFFF }, 0115 { CSS_VAL_YELLOW, 0xFFFFFF00 }, 0116 { CSS_VAL_TRANSPARENT, transparentColor }, 0117 { CSS_VAL_GREY, 0xff808080 }, 0118 { 0, 0 } 0119 }; 0120 0121 struct uiColors { 0122 int css_value; 0123 QPalette::ColorGroup group; 0124 QPalette::ColorRole role; 0125 }; 0126 0127 // CSS 2.1 system color mapping 0128 static const uiColors uimap[] = { 0129 // MDI background color 0130 { CSS_VAL_APPWORKSPACE, QPalette::Normal, QPalette::Mid }, 0131 // Button colors 0132 { CSS_VAL_BUTTONFACE, QPalette::Normal, QPalette::Button }, 0133 { CSS_VAL_BUTTONHIGHLIGHT, QPalette::Normal, QPalette::Light }, 0134 { CSS_VAL_BUTTONSHADOW, QPalette::Normal, QPalette::Dark }, 0135 { CSS_VAL_BUTTONTEXT, QPalette::Normal, QPalette::ButtonText }, 0136 // Disabled text 0137 { CSS_VAL_GRAYTEXT, QPalette::Disabled, QPalette::Text }, 0138 // Selected items 0139 { CSS_VAL_HIGHLIGHTTEXT, QPalette::Normal, QPalette::HighlightedText }, 0140 { CSS_VAL_HIGHLIGHT, QPalette::Normal, QPalette::Highlight }, 0141 // Tooltips 0142 { CSS_VAL_INFOBACKGROUND, QPalette::Normal, QPalette::ToolTipBase }, 0143 { CSS_VAL_INFOTEXT, QPalette::Normal, QPalette::ToolTipText }, 0144 // Menu colors 0145 { CSS_VAL_MENU, QPalette::Normal, QPalette::Window }, 0146 { CSS_VAL_MENUTEXT, QPalette::Normal, QPalette::Text }, 0147 // Scroll bar color 0148 { CSS_VAL_SCROLLBAR, QPalette::Normal, QPalette::Window }, 0149 // 3D elements 0150 { CSS_VAL_THREEDDARKSHADOW, QPalette::Normal, QPalette::Dark }, 0151 { CSS_VAL_THREEDFACE, QPalette::Normal, QPalette::Button }, 0152 { CSS_VAL_THREEDHIGHLIGHT, QPalette::Normal, QPalette::Light }, 0153 { CSS_VAL_THREEDLIGHTSHADOW, QPalette::Normal, QPalette::Midlight }, 0154 { CSS_VAL_THREEDSHADOW, QPalette::Normal, QPalette::Mid }, 0155 // Window background 0156 { CSS_VAL_WINDOW, QPalette::Normal, QPalette::Base }, 0157 // Window frame 0158 { CSS_VAL_WINDOWFRAME, QPalette::Normal, QPalette::Window }, 0159 // WindowText 0160 { CSS_VAL_WINDOWTEXT, QPalette::Normal, QPalette::Text }, 0161 { CSS_VAL_TEXT, QPalette::Normal, QPalette::Text }, 0162 { 0, QPalette::NColorGroups, QPalette::NColorRoles } 0163 }; 0164 0165 QColor khtml::colorForCSSValue(int css_value) 0166 { 0167 // try the regular ones first 0168 const colorMap *col = cmap; 0169 while (col->css_value && col->css_value != css_value) { 0170 ++col; 0171 } 0172 if (col->css_value) { 0173 return QColor::fromRgba(col->color); 0174 } else if (css_value == CSS_VAL_INVERT) { 0175 return QColor(); 0176 } 0177 0178 const uiColors *uicol = uimap; 0179 while (uicol->css_value && uicol->css_value != css_value) { 0180 ++uicol; 0181 } 0182 #ifndef APPLE_CHANGES 0183 if (!uicol->css_value) { 0184 switch (css_value) { 0185 case CSS_VAL_ACTIVEBORDER: 0186 return qApp->palette().color(QPalette::Normal, QPalette::Window); 0187 case CSS_VAL_ACTIVECAPTION: 0188 return KColorScheme(QPalette::Active, KColorScheme::Window).background(KColorScheme::ActiveBackground).color(); 0189 case CSS_VAL_CAPTIONTEXT: 0190 return KColorScheme(QPalette::Active, KColorScheme::Window).foreground(KColorScheme::ActiveText).color(); 0191 case CSS_VAL_INACTIVEBORDER: 0192 return qApp->palette().color(QPalette::Inactive, QPalette::Window); 0193 case CSS_VAL_INACTIVECAPTION: 0194 return KColorScheme(QPalette::Inactive, KColorScheme::Window).background().color(); 0195 case CSS_VAL_INACTIVECAPTIONTEXT: 0196 return KColorScheme(QPalette::Inactive, KColorScheme::Window).foreground().color(); 0197 case CSS_VAL_BACKGROUND: // Desktop background - no way to get this information from Plasma 0198 return qApp->palette().color(QPalette::Normal, QPalette::Highlight); 0199 default: 0200 return QColor(); 0201 } 0202 } 0203 #endif 0204 0205 const QPalette &pal = qApp->palette(); 0206 return pal.color(uicol->group, uicol->role); 0207 } 0208 0209 double calcHue(double temp1, double temp2, double hueVal) 0210 { 0211 if (hueVal < 0) { 0212 hueVal++; 0213 } else if (hueVal > 1) { 0214 hueVal--; 0215 } 0216 if (hueVal * 6 < 1) { 0217 return temp1 + (temp2 - temp1) * hueVal * 6; 0218 } 0219 if (hueVal * 2 < 1) { 0220 return temp2; 0221 } 0222 if (hueVal * 3 < 2) { 0223 return temp1 + (temp2 - temp1) * (2.0 / 3.0 - hueVal) * 6; 0224 } 0225 return temp1; 0226 } 0227 0228 // Explanation of this algorithm can be found in the CSS3 Color Module 0229 // specification at https://www.w3.org/TR/css3-color/#hsl-color with further 0230 // explanation available at https://en.wikipedia.org/wiki/HSL_and_HSV 0231 0232 // all values are in the range of 0 to 1.0 0233 QRgb khtml::qRgbaFromHsla(double h, double s, double l, double a) 0234 { 0235 double temp2 = l < 0.5 ? l * (1.0 + s) : l + s - l * s; 0236 double temp1 = 2.0 * l - temp2; 0237 0238 return qRgba(static_cast<int>(calcHue(temp1, temp2, h + 1.0 / 3.0) * 255), 0239 static_cast<int>(calcHue(temp1, temp2, h) * 255), 0240 static_cast<int>(calcHue(temp1, temp2, h - 1.0 / 3.0) * 255), 0241 static_cast<int>(a * 255)); 0242 } 0243 0244 /** finds out the background color of an element 0245 * @param obj render object 0246 * @return the background color. It is guaranteed that a valid color is returned. 0247 */ 0248 QColor khtml::retrieveBackgroundColor(const RenderObject *obj) 0249 { 0250 QColor result; 0251 while (!obj->isCanvas()) { 0252 result = obj->style()->backgroundColor(); 0253 if (result.isValid()) { 0254 return result; 0255 } 0256 0257 obj = obj->container(); 0258 }/*wend*/ 0259 0260 // everything transparent? Use base then. 0261 return obj->style()->palette().color(QPalette::Active, QPalette::Base); 0262 } 0263 0264 /** checks whether the given colors have enough contrast 0265 * @returns @p true if contrast is ok. 0266 */ 0267 bool khtml::hasSufficientContrast(const QColor &c1, const QColor &c2) 0268 { 0269 // New version from Germain Garand, better suited for contrast measurement 0270 #if 1 0271 0272 #define HUE_DISTANCE 40 0273 #define CONTRAST_DISTANCE 10 0274 0275 int h1, s1, v1, h2, s2, v2; 0276 int hdist = -CONTRAST_DISTANCE; 0277 c1.getHsv(&h1, &s1, &v1); 0278 c2.getHsv(&h2, &s2, &v2); 0279 if (h1 != -1 && h2 != -1) { // grey values have no hue 0280 hdist = qAbs(h1 - h2); 0281 if (hdist > 180) { 0282 hdist = 360 - hdist; 0283 } 0284 if (hdist < HUE_DISTANCE) { 0285 hdist -= HUE_DISTANCE; 0286 // see if they are high key or low key colours 0287 bool hk1 = h1 >= 45 && h1 <= 225; 0288 bool hk2 = h2 >= 45 && h2 <= 225; 0289 if (hk1 && hk2) { 0290 hdist = (5 * hdist) / 3; 0291 } else if (!hk1 && !hk2) { 0292 hdist = (7 * hdist) / 4; 0293 } 0294 } 0295 hdist = qMin(hdist, HUE_DISTANCE * 2); 0296 } 0297 return hdist + (qAbs(s1 - s2) * 128) / (160 + qMin(s1, s2)) + qAbs(v1 - v2) > CONTRAST_DISTANCE; 0298 0299 #undef CONTRAST_DISTANCE 0300 #undef HUE_DISTANCE 0301 0302 #else // orginal fast but primitive version by me (LS) 0303 0304 // ### arbitrary value, to be adapted if necessary (LS) 0305 #define CONTRAST_DISTANCE 32 0306 0307 if (qAbs(c1.Qt::red() - c2.Qt::red()) > CONTRAST_DISTANCE) { 0308 return true; 0309 } 0310 if (qAbs(c1.Qt::green() - c2.Qt::green()) > CONTRAST_DISTANCE) { 0311 return true; 0312 } 0313 if (qAbs(c1.Qt::blue() - c2.Qt::blue()) > CONTRAST_DISTANCE) { 0314 return true; 0315 } 0316 0317 return false; 0318 0319 #undef CONTRAST_DISTANCE 0320 0321 #endif 0322 }