File indexing completed on 2024-04-28 15:22:39
0001 /* 0002 * CSS Media Query 0003 * 0004 * Copyright (C) 2005, 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>. 0005 * (C) 2008 Germain Garand <germain@ebooksfrance.org> 0006 * Redistribution and use in source and binary forms, with or without 0007 * modification, are permitted provided that the following conditions 0008 * are met: 0009 * 1. Redistributions of source code must retain the above copyright 0010 * notice, this list of conditions and the following disclaimer. 0011 * 2. Redistributions in binary form must reproduce the above copyright 0012 * notice, this list of conditions and the following disclaimer in the 0013 * documentation and/or other materials provided with the distribution. 0014 * 0015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 0016 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 0017 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 0018 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 0019 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 0020 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 0021 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 0022 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 0023 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0024 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 0025 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0026 */ 0027 #include "css_mediaquery.h" 0028 #include "css_valueimpl.h" 0029 #include "css/css_stylesheetimpl.h" 0030 #include "css/cssparser.h" 0031 #include "cssstyleselector.h" 0032 #include "css/cssvalues.h" 0033 #include "khtml_part.h" 0034 #include "khtmlview.h" 0035 #include "rendering/render_style.h" 0036 #include "xml/dom_stringimpl.h" 0037 #include <QHash> 0038 #include <limits.h> 0039 #include <QDesktopWidget> 0040 #include <QColormap> 0041 0042 using namespace DOM; 0043 using namespace khtml; 0044 0045 MediaQuery::MediaQuery(Restrictor r, const DOMString &mediaType, QList<MediaQueryExp *> *exprs) 0046 : m_restrictor(r) 0047 , m_mediaType(mediaType) 0048 , m_expressions(exprs) 0049 { 0050 if (!m_expressions) { 0051 m_expressions = new QList<MediaQueryExp *>; 0052 } 0053 } 0054 0055 MediaQuery::~MediaQuery() 0056 { 0057 if (m_expressions) { 0058 qDeleteAll(*m_expressions); 0059 delete m_expressions; 0060 } 0061 } 0062 0063 bool MediaQuery::operator==(const MediaQuery &other) const 0064 { 0065 if (m_restrictor != other.m_restrictor 0066 || m_mediaType != other.m_mediaType 0067 || m_expressions->size() != other.m_expressions->size()) { 0068 return false; 0069 } 0070 0071 for (int i = 0; i < m_expressions->size(); ++i) { 0072 MediaQueryExp *exp = m_expressions->at(i); 0073 MediaQueryExp *oexp = other.m_expressions->at(i); 0074 if (!(*exp == *oexp)) { 0075 return false; 0076 } 0077 } 0078 0079 return true; 0080 } 0081 0082 DOMString MediaQuery::cssText() const 0083 { 0084 DOMString text; 0085 switch (m_restrictor) { 0086 case MediaQuery::Only: 0087 text += "only "; 0088 break; 0089 case MediaQuery::Not: 0090 text += "not "; 0091 break; 0092 case MediaQuery::None: 0093 default: 0094 break; 0095 } 0096 text += m_mediaType; 0097 for (int i = 0; i < m_expressions->size(); ++i) { 0098 MediaQueryExp *exp = m_expressions->at(i); 0099 text += " and ("; 0100 text += exp->mediaFeature(); 0101 if (exp->value()) { 0102 text += ": "; 0103 text += exp->value()->cssText(); 0104 } 0105 text += ")"; 0106 } 0107 return text; 0108 } 0109 0110 //--------------------------------------------------------------------------- 0111 0112 MediaQueryExp::MediaQueryExp(const DOMString &mediaFeature, ValueList *valueList) 0113 : m_mediaFeature(mediaFeature) 0114 , m_value(nullptr) 0115 { 0116 m_viewportDependent = (m_mediaFeature == "width" || 0117 m_mediaFeature == "height" || 0118 m_mediaFeature == "min-width" || 0119 m_mediaFeature == "min-height" || 0120 m_mediaFeature == "max-width" || 0121 m_mediaFeature == "max-height" || 0122 m_mediaFeature == "orientation" || 0123 m_mediaFeature == "aspect-ratio" || 0124 m_mediaFeature == "min-aspect-ratio" || 0125 m_mediaFeature == "max-aspect-ratio"); 0126 if (valueList) { 0127 if (valueList->size() == 1) { 0128 Value *value = valueList->current(); 0129 0130 if (value->id != 0) { 0131 m_value = new CSSPrimitiveValueImpl(value->id); 0132 } else if (value->unit == CSSPrimitiveValue::CSS_STRING) { 0133 m_value = new CSSPrimitiveValueImpl(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit); 0134 } else if ((value->unit >= CSSPrimitiveValue::CSS_NUMBER && 0135 value->unit <= CSSPrimitiveValue::CSS_KHZ) || 0136 value->unit == CSSPrimitiveValue::CSS_DPI || value->unit == CSSPrimitiveValue::CSS_DPCM) { 0137 m_value = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); 0138 } 0139 if (m_value) { 0140 m_value->ref(); 0141 } 0142 valueList->next(); 0143 } else if (valueList->size() > 1) { 0144 // create list of values 0145 // currently accepts only <integer>/<integer> 0146 0147 CSSValueListImpl *list = new CSSValueListImpl(); 0148 Value *value = nullptr; 0149 bool isValid = true; 0150 0151 while ((value = valueList->current()) && isValid) { 0152 if (value->unit == Value::Operator && value->iValue == '/') { 0153 list->append(new CSSPrimitiveValueImpl(DOMString("/"), CSSPrimitiveValue::CSS_STRING)); 0154 } else if (value->unit == CSSPrimitiveValue::CSS_NUMBER) { 0155 list->append(new CSSPrimitiveValueImpl(value->fValue, CSSPrimitiveValue::CSS_NUMBER)); 0156 } else { 0157 isValid = false; 0158 } 0159 0160 value = valueList->next(); 0161 } 0162 0163 if (isValid) { 0164 m_value = list; 0165 m_value->ref(); 0166 } else { 0167 delete list; 0168 } 0169 } 0170 } 0171 } 0172 0173 MediaQueryExp::~MediaQueryExp() 0174 { 0175 if (m_value) { 0176 m_value->deref(); 0177 } 0178 } 0179 0180 //--------------------------------------------------------------------------- 0181 0182 // when adding features, update also m_viewportDependent test if applicable 0183 #define CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(macro) \ 0184 macro(color, "color") \ 0185 macro(color_index, "color-index") \ 0186 macro(grid, "grid") \ 0187 macro(monochrome, "monochrome") \ 0188 macro(height, "height") \ 0189 macro(width, "width") \ 0190 macro(device_aspect_ratio, "device-aspect-ratio") \ 0191 macro(device_pixel_ratio, "-khtml-device-pixel-ratio") \ 0192 macro(device_height, "device-height") \ 0193 macro(device_width, "device-width") \ 0194 macro(orientation, "orientation") \ 0195 macro(aspect_ratio, "aspect-ratio") \ 0196 macro(resolution, "resolution") \ 0197 macro(scan, "scan") \ 0198 macro(max_color, "max-color") \ 0199 macro(max_color_index, "max-color-index") \ 0200 macro(max_device_aspect_ratio, "max-device-aspect-ratio") \ 0201 macro(max_device_pixel_ratio, "-khtml-max-device-pixel-ratio") \ 0202 macro(max_device_height, "max-device-height") \ 0203 macro(max_device_width, "max-device-width") \ 0204 macro(max_aspect_ratio, "max-aspect-ratio") \ 0205 macro(max_resolution, "max-resolution") \ 0206 macro(max_height, "max-height") \ 0207 macro(max_monochrome, "max-monochrome") \ 0208 macro(max_width, "max-width") \ 0209 macro(min_color, "min-color") \ 0210 macro(min_color_index, "min-color-index") \ 0211 macro(min_device_aspect_ratio, "min-device-aspect-ratio") \ 0212 macro(min_device_pixel_ratio, "-khtml-min-device-pixel-ratio") \ 0213 macro(min_device_height, "min-device-height") \ 0214 macro(min_device_width, "min-device-width") \ 0215 macro(min_resolution, "min-resolution") \ 0216 macro(min_aspect_ratio, "min-aspect-ratio") \ 0217 macro(min_height, "min-height") \ 0218 macro(min_monochrome, "min-monochrome") \ 0219 macro(min_width, "min-width") \ 0220 // end of macro 0221 0222 enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix }; 0223 0224 typedef bool (*EvalFunc)(CSSValueImpl *, RenderStyle *, KHTMLPart *, MediaFeaturePrefix); 0225 typedef QHash<DOMString, EvalFunc> FunctionMap; 0226 static FunctionMap *gFunctionMap = nullptr; 0227 0228 MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult) 0229 : m_part(nullptr) 0230 , m_style(nullptr) 0231 , m_expResult(mediaFeatureResult) 0232 { 0233 } 0234 0235 MediaQueryEvaluator:: MediaQueryEvaluator(const DOMString &acceptedMediaType, bool mediaFeatureResult) 0236 : m_mediaType(acceptedMediaType) 0237 , m_part(nullptr) 0238 , m_style(nullptr) 0239 , m_expResult(mediaFeatureResult) 0240 { 0241 } 0242 0243 MediaQueryEvaluator:: MediaQueryEvaluator(const char *acceptedMediaType, bool mediaFeatureResult) 0244 : m_mediaType(acceptedMediaType) 0245 , m_part(nullptr) 0246 , m_style(nullptr) 0247 , m_expResult(mediaFeatureResult) 0248 { 0249 } 0250 0251 MediaQueryEvaluator:: MediaQueryEvaluator(const DOMString &acceptedMediaType, KHTMLPart *part, RenderStyle *style) 0252 : m_mediaType(acceptedMediaType.lower()) 0253 , m_part(part) 0254 , m_style(style) 0255 , m_expResult(false) // doesn't matter when we have m_part and m_style 0256 { 0257 } 0258 0259 MediaQueryEvaluator::~MediaQueryEvaluator() 0260 { 0261 } 0262 0263 bool MediaQueryEvaluator::mediaTypeMatch(const DOMString &mediaTypeToMatch) const 0264 { 0265 return mediaTypeToMatch.isEmpty() 0266 || !strcasecmp("all", mediaTypeToMatch) 0267 || !strcasecmp(m_mediaType, mediaTypeToMatch); 0268 } 0269 0270 bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char *mediaTypeToMatch) const 0271 { 0272 // Like mediaTypeMatch, but without the special cases for "" and "all". 0273 assert(mediaTypeToMatch); 0274 assert(mediaTypeToMatch[0] != '\0'); 0275 assert(strcasecmp(DOMString("all"), mediaTypeToMatch)); 0276 return !strcasecmp(m_mediaType, mediaTypeToMatch); 0277 } 0278 0279 static bool applyRestrictor(MediaQuery::Restrictor r, bool value) 0280 { 0281 return r == MediaQuery::Not ? !value : value; 0282 } 0283 0284 bool MediaQueryEvaluator::eval(const MediaListImpl *mediaList, CSSStyleSelector *styleSelector) const 0285 { 0286 if (!mediaList) { 0287 return true; 0288 } 0289 0290 const QList<MediaQuery *> *queries = mediaList->mediaQueries(); 0291 if (!queries->size()) { 0292 return true; // empty query list evaluates to true 0293 } 0294 0295 // iterate over queries, stop if any of them eval to true (OR semantics) 0296 bool result = false; 0297 for (int i = 0; i < queries->size() && !result; ++i) { 0298 MediaQuery *query = queries->at(i); 0299 if (mediaTypeMatch(query->mediaType())) { 0300 const QList<MediaQueryExp *> *exps = query->expressions(); 0301 // iterate through expressions, stop if any of them eval to false 0302 // (AND semantics) 0303 int j = 0; 0304 for (; j < exps->size(); ++j) { 0305 bool exprResult = eval(exps->at(j)); 0306 if (styleSelector && exps->at(j)->isViewportDependent()) { 0307 styleSelector->addViewportDependentMediaQueryResult(exps->at(j), exprResult); 0308 } 0309 if (!exprResult) { 0310 break; 0311 } 0312 } 0313 0314 // assume true if we are at the end of the list, 0315 // otherwise assume false 0316 result = applyRestrictor(query->restrictor(), exps->size() == j); 0317 } else { 0318 result = applyRestrictor(query->restrictor(), false); 0319 } 0320 } 0321 0322 return result; 0323 } 0324 0325 static bool parseAspectRatio(CSSValueImpl *value, int &h, int &v) 0326 { 0327 if (value->isValueList()) { 0328 CSSValueListImpl *valueList = static_cast<CSSValueListImpl *>(value); 0329 if (valueList->length() == 3) { 0330 CSSValueImpl *i0 = valueList->item(0); 0331 CSSValueImpl *i1 = valueList->item(1); 0332 CSSValueImpl *i2 = valueList->item(2); 0333 if (i0->isPrimitiveValue() && static_cast<CSSPrimitiveValueImpl *>(i0)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER 0334 && i1->isPrimitiveValue() && static_cast<CSSPrimitiveValueImpl *>(i1)->primitiveType() == CSSPrimitiveValue::CSS_STRING 0335 && i2->isPrimitiveValue() && static_cast<CSSPrimitiveValueImpl *>(i2)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) { 0336 DOMString str = static_cast<CSSPrimitiveValueImpl *>(i1)->getStringValue(); 0337 if (!str.isNull() && str.length() == 1 && str[0] == '/') { 0338 h = (int)static_cast<CSSPrimitiveValueImpl *>(i0)->floatValue(CSSPrimitiveValue::CSS_NUMBER); 0339 v = (int)static_cast<CSSPrimitiveValueImpl *>(i2)->floatValue(CSSPrimitiveValue::CSS_NUMBER); 0340 return true; 0341 } 0342 } 0343 } 0344 } 0345 return false; 0346 } 0347 0348 template<typename T> 0349 bool compareValue(T a, T b, MediaFeaturePrefix op) 0350 { 0351 switch (op) { 0352 case MinPrefix: 0353 return a >= b; 0354 case MaxPrefix: 0355 return a <= b; 0356 case NoPrefix: 0357 return a == b; 0358 } 0359 return false; 0360 } 0361 0362 static bool numberValue(CSSValueImpl *value, float &result) 0363 { 0364 if (value->isPrimitiveValue() 0365 && static_cast<CSSPrimitiveValueImpl *>(value)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) { 0366 result = static_cast<CSSPrimitiveValueImpl *>(value)->floatValue(CSSPrimitiveValue::CSS_NUMBER); 0367 return true; 0368 } 0369 return false; 0370 } 0371 0372 static bool color_indexMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op) 0373 { 0374 KHTMLPart *rootPart = part; 0375 while (rootPart->parentPart()) { 0376 rootPart = rootPart->parentPart(); 0377 } 0378 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle()); 0379 QPaintDevice *pd = doc->paintDevice(); 0380 bool printing = pd ? (pd->devType() == QInternal::Printer) : false; 0381 unsigned int numColors = 0; 0382 if (printing) { 0383 numColors = pd->colorCount(); 0384 } else { 0385 int sn = QApplication::desktop()->screenNumber(rootPart->view()); 0386 numColors = QApplication::desktop()->screen(sn)->colorCount(); 0387 } 0388 if (numColors == INT_MAX) { 0389 numColors = UINT_MAX; 0390 } 0391 if (value) { 0392 float number = 0; 0393 return numberValue(value, number) && compareValue(numColors, static_cast<unsigned int>(number), op); 0394 } 0395 0396 return numColors; 0397 } 0398 0399 static bool colorMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op) 0400 { 0401 KHTMLPart *rootPart = part; 0402 while (rootPart->parentPart()) { 0403 rootPart = rootPart->parentPart(); 0404 } 0405 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle()); 0406 QPaintDevice *pd = doc->paintDevice(); 0407 bool printing = pd ? (pd->devType() == QInternal::Printer) : false; 0408 int bitsPerComponent = 0; 0409 if (printing) { 0410 if (pd->colorCount() > 2) { 0411 bitsPerComponent = pd->depth() / 3; 0412 } 0413 // assume printer is either b&w or color. 0414 } else { 0415 int sn = QApplication::desktop()->screenNumber(rootPart->view()); 0416 if (QColormap::instance(sn).mode() != QColormap::Gray) { 0417 bitsPerComponent = QApplication::desktop()->screen(sn)->depth() / 3; 0418 } 0419 } 0420 if (value && bitsPerComponent) { 0421 float number = 0; 0422 return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op); 0423 } 0424 return bitsPerComponent; 0425 } 0426 0427 static bool monochromeMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op) 0428 { 0429 KHTMLPart *rootPart = part; 0430 while (rootPart->parentPart()) { 0431 rootPart = rootPart->parentPart(); 0432 } 0433 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle()); 0434 QPaintDevice *pd = doc->paintDevice(); 0435 bool printing = pd ? (pd->devType() == QInternal::Printer) : false; 0436 int depth = 0; 0437 if (printing) { 0438 if (pd->colorCount() < 2) { 0439 depth = 1; 0440 } 0441 // assume printer is either b&w or color. 0442 } else { 0443 int sn = QApplication::desktop()->screenNumber(rootPart->view()); 0444 if (QApplication::desktop()->screen(sn)->depth() == 1) { 0445 depth = 1; 0446 } else if (QColormap::instance(sn).mode() == QColormap::Gray) { 0447 depth = QApplication::desktop()->screen(sn)->depth(); 0448 } 0449 } 0450 if (value) { 0451 float number = 0; 0452 return numberValue(value, number) && compareValue(depth, static_cast<int>(number), op); 0453 } 0454 return depth; 0455 } 0456 0457 static bool device_aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op) 0458 { 0459 if (value) { 0460 KHTMLPart *rootPart = part; 0461 while (rootPart->parentPart()) { 0462 rootPart = rootPart->parentPart(); 0463 } 0464 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle()); 0465 QPaintDevice *pd = doc->paintDevice(); 0466 bool printing = pd ? (pd->devType() == QInternal::Printer) : false; 0467 QRect sg; 0468 int h = 0, v = 0; 0469 if (printing) { 0470 sg = QRect(0, 0, pd->width(), pd->height()); 0471 } else { 0472 sg = QApplication::desktop()->screen(QApplication::desktop()->screenNumber(rootPart->view()))->rect(); 0473 } 0474 if (parseAspectRatio(value, h, v)) { 0475 return v != 0 && compareValue(sg.width() * v, sg.height() * h, op); 0476 } 0477 return false; 0478 } 0479 0480 // ({,min-,max-}device-aspect-ratio) 0481 // assume if we have a device, its aspect ratio is non-zero 0482 return true; 0483 } 0484 0485 static bool aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op) 0486 { 0487 if (value) { 0488 KHTMLPart *rootPart = part; 0489 while (rootPart->parentPart()) { 0490 rootPart = rootPart->parentPart(); 0491 } 0492 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle()); 0493 QPaintDevice *pd = doc->paintDevice(); 0494 bool printing = pd ? (pd->devType() == QInternal::Printer) : false; 0495 QSize vs; 0496 int h = 0, v = 0; 0497 if (printing) { 0498 vs = QSize(pd->width(), pd->height()); 0499 } else { 0500 vs = QSize(part->view()->visibleWidth(), part->view()->visibleHeight()); 0501 } 0502 if (parseAspectRatio(value, h, v)) { 0503 return v != 0 && compareValue(vs.width() * v, vs.height() * h, op); 0504 } 0505 return false; 0506 } 0507 // ({,min-,max-}aspect-ratio) 0508 // assume if we have a viewport, its aspect ratio is non-zero 0509 return true; 0510 } 0511 0512 static bool orientationMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0513 { 0514 if (value) { 0515 CSSPrimitiveValueImpl *pv = static_cast<CSSPrimitiveValueImpl *>(value); 0516 if (!value->isPrimitiveValue() || pv->primitiveType() != CSSPrimitiveValue::CSS_IDENT || 0517 (pv->getIdent() != CSS_VAL_PORTRAIT && pv->getIdent() != CSS_VAL_LANDSCAPE)) { 0518 return false; 0519 } 0520 0521 KHTMLPart *rootPart = part; 0522 while (rootPart->parentPart()) { 0523 rootPart = rootPart->parentPart(); 0524 } 0525 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle()); 0526 QPaintDevice *pd = doc->paintDevice(); 0527 bool printing = pd ? (pd->devType() == QInternal::Printer) : false; 0528 if (printing) { 0529 if (pd->width() > pd->height()) { 0530 return (pv->getIdent() == CSS_VAL_LANDSCAPE); 0531 } 0532 } else { 0533 if (part->view()->visibleWidth() > part->view()->visibleHeight()) { 0534 return (pv->getIdent() == CSS_VAL_LANDSCAPE); 0535 } 0536 } 0537 return (pv->getIdent() == CSS_VAL_PORTRAIT); 0538 } 0539 return false; 0540 } 0541 0542 static bool device_pixel_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op) 0543 { 0544 if (value) { 0545 return value->isPrimitiveValue() && compareValue(part->zoomFactor() / 100.0, static_cast<CSSPrimitiveValueImpl *>(value)->floatValue(), op); 0546 } 0547 0548 return part->zoomFactor() != 0; 0549 } 0550 0551 static bool gridMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart * /*part*/, MediaFeaturePrefix op) 0552 { 0553 // if output device is bitmap, grid: 0 == true 0554 // assume we have bitmap device 0555 float number; 0556 if (value && numberValue(value, number)) { 0557 return compareValue(static_cast<int>(number), 0, op); 0558 } 0559 return false; 0560 } 0561 0562 // for printing media, we'll make the approximation that the device height == the paged box's height 0563 static bool device_heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix op) 0564 { 0565 if (value) { 0566 KHTMLPart *rootPart = part; 0567 while (rootPart->parentPart()) { 0568 rootPart = rootPart->parentPart(); 0569 } 0570 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle()); 0571 QPaintDevice *pd = doc->paintDevice(); 0572 bool printing = pd ? (pd->devType() == QInternal::Printer) : false; 0573 int height; 0574 if (printing) { 0575 height = pd->height(); 0576 } else { 0577 height = QApplication::desktop()->screen(QApplication::desktop()->screenNumber(rootPart->view()))->rect().height(); 0578 doc = static_cast<DOM::DocumentImpl *>(part->document().handle()); 0579 } 0580 int logicalDpiY = doc->logicalDpiY(); 0581 return value->isPrimitiveValue() && compareValue(height, static_cast<CSSPrimitiveValueImpl *>(value)->computeLength(style, style, logicalDpiY), op); 0582 } 0583 // ({,min-,max-}device-height) 0584 // assume if we have a device, assume non-zero 0585 return true; 0586 } 0587 0588 static bool device_widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix op) 0589 { 0590 if (value) { 0591 KHTMLPart *rootPart = part; 0592 while (rootPart->parentPart()) { 0593 rootPart = rootPart->parentPart(); 0594 } 0595 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle()); 0596 QPaintDevice *pd = doc->paintDevice(); 0597 bool printing = pd ? (pd->devType() == QInternal::Printer) : false; 0598 int width; 0599 if (printing) { 0600 width = pd->width(); 0601 } else { 0602 width = QApplication::desktop()->screen(QApplication::desktop()->screenNumber(rootPart->view()))->rect().width(); 0603 doc = static_cast<DOM::DocumentImpl *>(part->document().handle()); 0604 } 0605 int logicalDpiY = doc->logicalDpiY(); 0606 return value->isPrimitiveValue() && compareValue(width, static_cast<CSSPrimitiveValueImpl *>(value)->computeLength(style, style, logicalDpiY), op); 0607 } 0608 // ({,min-,max-}device-width) 0609 // assume if we have a device, assume non-zero 0610 return true; 0611 } 0612 0613 // cf. https://www.w3.org/TR/css3-mediaqueries/#device-width 0614 // "For continuous media, this is the width of the viewport (as described by CSS2, section 9.1.1 [CSS2]). 0615 // For paged media, this is the width of the page box (as described by CSS2, section 13.2 [CSS2])" 0616 0617 static bool widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix op) 0618 { 0619 KHTMLPart *rootPart = part; 0620 while (rootPart->parentPart()) { 0621 rootPart = rootPart->parentPart(); 0622 } 0623 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle()); 0624 QPaintDevice *pd = doc->paintDevice(); 0625 bool printing = pd ? (pd->devType() == QInternal::Printer) : false; 0626 int width; 0627 if (printing) { 0628 width = pd->width(); 0629 } else { 0630 width = part->view()->visibleWidth(); 0631 doc = static_cast<DOM::DocumentImpl *>(part->document().handle()); 0632 } 0633 int logicalDpiY = doc->logicalDpiY(); 0634 if (value) { 0635 return value->isPrimitiveValue() && compareValue(width, static_cast<CSSPrimitiveValueImpl *>(value)->computeLength(style, style, logicalDpiY), op); 0636 } 0637 0638 return width > 0; 0639 } 0640 0641 static bool heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix op) 0642 { 0643 KHTMLPart *rootPart = part; 0644 while (rootPart->parentPart()) { 0645 rootPart = rootPart->parentPart(); 0646 } 0647 DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle()); 0648 QPaintDevice *pd = doc->paintDevice(); 0649 bool printing = pd ? (pd->devType() == QInternal::Printer) : false; 0650 int height; 0651 if (printing) { 0652 height = pd->height(); 0653 } else { 0654 height = part->view()->visibleHeight(); 0655 doc = static_cast<DOM::DocumentImpl *>(part->document().handle()); 0656 } 0657 int logicalDpiY = doc->logicalDpiY(); 0658 if (value) { 0659 return value->isPrimitiveValue() && compareValue(height, static_cast<CSSPrimitiveValueImpl *>(value)->computeLength(style, style, logicalDpiY), op); 0660 } 0661 0662 return height > 0; 0663 } 0664 0665 static bool resolutionMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op) 0666 { 0667 DOM::DocumentImpl *d = static_cast<DOM::DocumentImpl *>(part->document().handle()); 0668 int logicalDpiY = d ? d->logicalDpiY() : 0; 0669 0670 if (value && logicalDpiY) { 0671 return value->isPrimitiveValue() && compareValue(logicalDpiY, static_cast<CSSPrimitiveValueImpl *>(value)->getDPIResolution(), op); 0672 } 0673 0674 return logicalDpiY != 0; 0675 } 0676 0677 static bool scanMediaFeatureEval(CSSValueImpl * /*value*/, RenderStyle *, KHTMLPart * /*part*/, MediaFeaturePrefix) 0678 { 0679 // no support for tv media type. 0680 return false; 0681 } 0682 0683 // rest of the functions are trampolines which set the prefix according to the media feature expression used 0684 0685 static bool min_color_indexMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0686 { 0687 return color_indexMediaFeatureEval(value, style, part, MinPrefix); 0688 } 0689 0690 static bool max_color_indexMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0691 { 0692 return color_indexMediaFeatureEval(value, style, part, MinPrefix); 0693 } 0694 0695 static bool min_colorMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0696 { 0697 return colorMediaFeatureEval(value, style, part, MinPrefix); 0698 } 0699 0700 static bool max_colorMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0701 { 0702 return colorMediaFeatureEval(value, style, part, MaxPrefix); 0703 } 0704 0705 static bool min_monochromeMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0706 { 0707 return monochromeMediaFeatureEval(value, style, part, MinPrefix); 0708 } 0709 0710 static bool max_monochromeMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0711 { 0712 return monochromeMediaFeatureEval(value, style, part, MaxPrefix); 0713 } 0714 0715 static bool min_device_aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0716 { 0717 return device_aspect_ratioMediaFeatureEval(value, style, part, MinPrefix); 0718 } 0719 0720 static bool max_device_aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0721 { 0722 return device_aspect_ratioMediaFeatureEval(value, style, part, MaxPrefix); 0723 } 0724 0725 static bool min_aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0726 { 0727 return aspect_ratioMediaFeatureEval(value, style, part, MinPrefix); 0728 } 0729 0730 static bool max_aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0731 { 0732 return aspect_ratioMediaFeatureEval(value, style, part, MaxPrefix); 0733 } 0734 0735 static bool min_device_pixel_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0736 { 0737 return device_pixel_ratioMediaFeatureEval(value, style, part, MinPrefix); 0738 } 0739 0740 static bool max_device_pixel_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0741 { 0742 return device_pixel_ratioMediaFeatureEval(value, style, part, MaxPrefix); 0743 } 0744 0745 static bool min_heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0746 { 0747 return heightMediaFeatureEval(value, style, part, MinPrefix); 0748 } 0749 0750 static bool max_heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0751 { 0752 return heightMediaFeatureEval(value, style, part, MaxPrefix); 0753 } 0754 0755 static bool min_widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0756 { 0757 return widthMediaFeatureEval(value, style, part, MinPrefix); 0758 } 0759 0760 static bool max_widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0761 { 0762 return widthMediaFeatureEval(value, style, part, MaxPrefix); 0763 } 0764 0765 static bool min_device_heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0766 { 0767 return device_heightMediaFeatureEval(value, style, part, MinPrefix); 0768 } 0769 0770 static bool max_device_heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0771 { 0772 return device_heightMediaFeatureEval(value, style, part, MaxPrefix); 0773 } 0774 0775 static bool min_device_widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0776 { 0777 return device_widthMediaFeatureEval(value, style, part, MinPrefix); 0778 } 0779 0780 static bool max_device_widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0781 { 0782 return device_widthMediaFeatureEval(value, style, part, MaxPrefix); 0783 } 0784 0785 static bool min_resolutionMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0786 { 0787 return resolutionMediaFeatureEval(value, style, part, MinPrefix); 0788 } 0789 0790 static bool max_resolutionMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/) 0791 { 0792 return resolutionMediaFeatureEval(value, style, part, MaxPrefix); 0793 } 0794 0795 static void createFunctionMap() 0796 { 0797 // Create the table. 0798 gFunctionMap = new FunctionMap; 0799 #define ADD_TO_FUNCTIONMAP(name, str) \ 0800 gFunctionMap->insert(DOMString(str), name##MediaFeatureEval); 0801 CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP); 0802 #undef ADD_TO_FUNCTIONMAP 0803 } 0804 0805 void MediaQueryEvaluator::cleanup() // static 0806 { 0807 delete gFunctionMap; 0808 gFunctionMap = nullptr; 0809 } 0810 0811 bool MediaQueryEvaluator::eval(const MediaQueryExp *expr) const 0812 { 0813 if (!m_part || !m_style) { 0814 return m_expResult; 0815 } 0816 0817 if (!gFunctionMap) { 0818 createFunctionMap(); 0819 } 0820 0821 // call the media feature evaluation function. Assume no prefix 0822 // and let trampoline functions override the prefix if prefix is 0823 // used 0824 FunctionMap::ConstIterator func = gFunctionMap->constFind(expr->mediaFeature()); 0825 if (func != gFunctionMap->constEnd()) { 0826 return (*func.value())(expr->value(), m_style, m_part, NoPrefix); 0827 } 0828 0829 return false; 0830 }