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 }