KHtml

css_mediaquery.cpp
1 /*
2  * CSS Media Query
3  *
4  * Copyright (C) 2005, 2006 Kimmo Kinnunen <[email protected]>.
5  * (C) 2008 Germain Garand <[email protected]>
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include "css_mediaquery.h"
28 #include "css_valueimpl.h"
29 #include "css/css_stylesheetimpl.h"
30 #include "css/cssparser.h"
31 #include "cssstyleselector.h"
32 #include "css/cssvalues.h"
33 #include "khtml_part.h"
34 #include "khtmlview.h"
35 #include "rendering/render_style.h"
36 #include "xml/dom_stringimpl.h"
37 #include <QHash>
38 #include <limits.h>
39 #include <QDesktopWidget>
40 #include <QColormap>
41 
42 using namespace DOM;
43 using namespace khtml;
44 
45 MediaQuery::MediaQuery(Restrictor r, const DOMString &mediaType, QList<MediaQueryExp *> *exprs)
46  : m_restrictor(r)
47  , m_mediaType(mediaType)
48  , m_expressions(exprs)
49 {
50  if (!m_expressions) {
51  m_expressions = new QList<MediaQueryExp *>;
52  }
53 }
54 
55 MediaQuery::~MediaQuery()
56 {
57  if (m_expressions) {
58  qDeleteAll(*m_expressions);
59  delete m_expressions;
60  }
61 }
62 
63 bool MediaQuery::operator==(const MediaQuery &other) const
64 {
65  if (m_restrictor != other.m_restrictor
66  || m_mediaType != other.m_mediaType
67  || m_expressions->size() != other.m_expressions->size()) {
68  return false;
69  }
70 
71  for (int i = 0; i < m_expressions->size(); ++i) {
72  MediaQueryExp *exp = m_expressions->at(i);
73  MediaQueryExp *oexp = other.m_expressions->at(i);
74  if (!(*exp == *oexp)) {
75  return false;
76  }
77  }
78 
79  return true;
80 }
81 
82 DOMString MediaQuery::cssText() const
83 {
84  DOMString text;
85  switch (m_restrictor) {
86  case MediaQuery::Only:
87  text += "only ";
88  break;
89  case MediaQuery::Not:
90  text += "not ";
91  break;
92  case MediaQuery::None:
93  default:
94  break;
95  }
96  text += m_mediaType;
97  for (int i = 0; i < m_expressions->size(); ++i) {
98  MediaQueryExp *exp = m_expressions->at(i);
99  text += " and (";
100  text += exp->mediaFeature();
101  if (exp->value()) {
102  text += ": ";
103  text += exp->value()->cssText();
104  }
105  text += ")";
106  }
107  return text;
108 }
109 
110 //---------------------------------------------------------------------------
111 
112 MediaQueryExp::MediaQueryExp(const DOMString &mediaFeature, ValueList *valueList)
113  : m_mediaFeature(mediaFeature)
114  , m_value(nullptr)
115 {
116  m_viewportDependent = (m_mediaFeature == "width" ||
117  m_mediaFeature == "height" ||
118  m_mediaFeature == "min-width" ||
119  m_mediaFeature == "min-height" ||
120  m_mediaFeature == "max-width" ||
121  m_mediaFeature == "max-height" ||
122  m_mediaFeature == "orientation" ||
123  m_mediaFeature == "aspect-ratio" ||
124  m_mediaFeature == "min-aspect-ratio" ||
125  m_mediaFeature == "max-aspect-ratio");
126  if (valueList) {
127  if (valueList->size() == 1) {
128  Value *value = valueList->current();
129 
130  if (value->id != 0) {
131  m_value = new CSSPrimitiveValueImpl(value->id);
132  } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
133  m_value = new CSSPrimitiveValueImpl(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit);
134  } else if ((value->unit >= CSSPrimitiveValue::CSS_NUMBER &&
135  value->unit <= CSSPrimitiveValue::CSS_KHZ) ||
136  value->unit == CSSPrimitiveValue::CSS_DPI || value->unit == CSSPrimitiveValue::CSS_DPCM) {
137  m_value = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
138  }
139  if (m_value) {
140  m_value->ref();
141  }
142  valueList->next();
143  } else if (valueList->size() > 1) {
144  // create list of values
145  // currently accepts only <integer>/<integer>
146 
147  CSSValueListImpl *list = new CSSValueListImpl();
148  Value *value = nullptr;
149  bool isValid = true;
150 
151  while ((value = valueList->current()) && isValid) {
152  if (value->unit == Value::Operator && value->iValue == '/') {
153  list->append(new CSSPrimitiveValueImpl(DOMString("/"), CSSPrimitiveValue::CSS_STRING));
154  } else if (value->unit == CSSPrimitiveValue::CSS_NUMBER) {
155  list->append(new CSSPrimitiveValueImpl(value->fValue, CSSPrimitiveValue::CSS_NUMBER));
156  } else {
157  isValid = false;
158  }
159 
160  value = valueList->next();
161  }
162 
163  if (isValid) {
164  m_value = list;
165  m_value->ref();
166  } else {
167  delete list;
168  }
169  }
170  }
171 }
172 
173 MediaQueryExp::~MediaQueryExp()
174 {
175  if (m_value) {
176  m_value->deref();
177  }
178 }
179 
180 //---------------------------------------------------------------------------
181 
182 // when adding features, update also m_viewportDependent test if applicable
183 #define CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(macro) \
184  macro(color, "color") \
185  macro(color_index, "color-index") \
186  macro(grid, "grid") \
187  macro(monochrome, "monochrome") \
188  macro(height, "height") \
189  macro(width, "width") \
190  macro(device_aspect_ratio, "device-aspect-ratio") \
191  macro(device_pixel_ratio, "-khtml-device-pixel-ratio") \
192  macro(device_height, "device-height") \
193  macro(device_width, "device-width") \
194  macro(orientation, "orientation") \
195  macro(aspect_ratio, "aspect-ratio") \
196  macro(resolution, "resolution") \
197  macro(scan, "scan") \
198  macro(max_color, "max-color") \
199  macro(max_color_index, "max-color-index") \
200  macro(max_device_aspect_ratio, "max-device-aspect-ratio") \
201  macro(max_device_pixel_ratio, "-khtml-max-device-pixel-ratio") \
202  macro(max_device_height, "max-device-height") \
203  macro(max_device_width, "max-device-width") \
204  macro(max_aspect_ratio, "max-aspect-ratio") \
205  macro(max_resolution, "max-resolution") \
206  macro(max_height, "max-height") \
207  macro(max_monochrome, "max-monochrome") \
208  macro(max_width, "max-width") \
209  macro(min_color, "min-color") \
210  macro(min_color_index, "min-color-index") \
211  macro(min_device_aspect_ratio, "min-device-aspect-ratio") \
212  macro(min_device_pixel_ratio, "-khtml-min-device-pixel-ratio") \
213  macro(min_device_height, "min-device-height") \
214  macro(min_device_width, "min-device-width") \
215  macro(min_resolution, "min-resolution") \
216  macro(min_aspect_ratio, "min-aspect-ratio") \
217  macro(min_height, "min-height") \
218  macro(min_monochrome, "min-monochrome") \
219  macro(min_width, "min-width") \
220  // end of macro
221 
222 enum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix };
223 
224 typedef bool (*EvalFunc)(CSSValueImpl *, RenderStyle *, KHTMLPart *, MediaFeaturePrefix);
226 static FunctionMap *gFunctionMap = nullptr;
227 
228 MediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult)
229  : m_part(nullptr)
230  , m_style(nullptr)
231  , m_expResult(mediaFeatureResult)
232 {
233 }
234 
235 MediaQueryEvaluator:: MediaQueryEvaluator(const DOMString &acceptedMediaType, bool mediaFeatureResult)
236  : m_mediaType(acceptedMediaType)
237  , m_part(nullptr)
238  , m_style(nullptr)
239  , m_expResult(mediaFeatureResult)
240 {
241 }
242 
243 MediaQueryEvaluator:: MediaQueryEvaluator(const char *acceptedMediaType, bool mediaFeatureResult)
244  : m_mediaType(acceptedMediaType)
245  , m_part(nullptr)
246  , m_style(nullptr)
247  , m_expResult(mediaFeatureResult)
248 {
249 }
250 
251 MediaQueryEvaluator:: MediaQueryEvaluator(const DOMString &acceptedMediaType, KHTMLPart *part, RenderStyle *style)
252  : m_mediaType(acceptedMediaType.lower())
253  , m_part(part)
254  , m_style(style)
255  , m_expResult(false) // doesn't matter when we have m_part and m_style
256 {
257 }
258 
259 MediaQueryEvaluator::~MediaQueryEvaluator()
260 {
261 }
262 
263 bool MediaQueryEvaluator::mediaTypeMatch(const DOMString &mediaTypeToMatch) const
264 {
265  return mediaTypeToMatch.isEmpty()
266  || !strcasecmp("all", mediaTypeToMatch)
267  || !strcasecmp(m_mediaType, mediaTypeToMatch);
268 }
269 
270 bool MediaQueryEvaluator::mediaTypeMatchSpecific(const char *mediaTypeToMatch) const
271 {
272  // Like mediaTypeMatch, but without the special cases for "" and "all".
273  assert(mediaTypeToMatch);
274  assert(mediaTypeToMatch[0] != '\0');
275  assert(strcasecmp(DOMString("all"), mediaTypeToMatch));
276  return !strcasecmp(m_mediaType, mediaTypeToMatch);
277 }
278 
279 static bool applyRestrictor(MediaQuery::Restrictor r, bool value)
280 {
281  return r == MediaQuery::Not ? !value : value;
282 }
283 
284 bool MediaQueryEvaluator::eval(const MediaListImpl *mediaList, CSSStyleSelector *styleSelector) const
285 {
286  if (!mediaList) {
287  return true;
288  }
289 
290  const QList<MediaQuery *> *queries = mediaList->mediaQueries();
291  if (!queries->size()) {
292  return true; // empty query list evaluates to true
293  }
294 
295  // iterate over queries, stop if any of them eval to true (OR semantics)
296  bool result = false;
297  for (int i = 0; i < queries->size() && !result; ++i) {
298  MediaQuery *query = queries->at(i);
299  if (mediaTypeMatch(query->mediaType())) {
300  const QList<MediaQueryExp *> *exps = query->expressions();
301  // iterate through expressions, stop if any of them eval to false
302  // (AND semantics)
303  int j = 0;
304  for (; j < exps->size(); ++j) {
305  bool exprResult = eval(exps->at(j));
306  if (styleSelector && exps->at(j)->isViewportDependent()) {
307  styleSelector->addViewportDependentMediaQueryResult(exps->at(j), exprResult);
308  }
309  if (!exprResult) {
310  break;
311  }
312  }
313 
314  // assume true if we are at the end of the list,
315  // otherwise assume false
316  result = applyRestrictor(query->restrictor(), exps->size() == j);
317  } else {
318  result = applyRestrictor(query->restrictor(), false);
319  }
320  }
321 
322  return result;
323 }
324 
325 static bool parseAspectRatio(CSSValueImpl *value, int &h, int &v)
326 {
327  if (value->isValueList()) {
328  CSSValueListImpl *valueList = static_cast<CSSValueListImpl *>(value);
329  if (valueList->length() == 3) {
330  CSSValueImpl *i0 = valueList->item(0);
331  CSSValueImpl *i1 = valueList->item(1);
332  CSSValueImpl *i2 = valueList->item(2);
333  if (i0->isPrimitiveValue() && static_cast<CSSPrimitiveValueImpl *>(i0)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER
334  && i1->isPrimitiveValue() && static_cast<CSSPrimitiveValueImpl *>(i1)->primitiveType() == CSSPrimitiveValue::CSS_STRING
335  && i2->isPrimitiveValue() && static_cast<CSSPrimitiveValueImpl *>(i2)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) {
336  DOMString str = static_cast<CSSPrimitiveValueImpl *>(i1)->getStringValue();
337  if (!str.isNull() && str.length() == 1 && str[0] == '/') {
338  h = (int)static_cast<CSSPrimitiveValueImpl *>(i0)->floatValue(CSSPrimitiveValue::CSS_NUMBER);
339  v = (int)static_cast<CSSPrimitiveValueImpl *>(i2)->floatValue(CSSPrimitiveValue::CSS_NUMBER);
340  return true;
341  }
342  }
343  }
344  }
345  return false;
346 }
347 
348 template<typename T>
349 bool compareValue(T a, T b, MediaFeaturePrefix op)
350 {
351  switch (op) {
352  case MinPrefix:
353  return a >= b;
354  case MaxPrefix:
355  return a <= b;
356  case NoPrefix:
357  return a == b;
358  }
359  return false;
360 }
361 
362 static bool numberValue(CSSValueImpl *value, float &result)
363 {
364  if (value->isPrimitiveValue()
365  && static_cast<CSSPrimitiveValueImpl *>(value)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) {
366  result = static_cast<CSSPrimitiveValueImpl *>(value)->floatValue(CSSPrimitiveValue::CSS_NUMBER);
367  return true;
368  }
369  return false;
370 }
371 
372 static bool color_indexMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op)
373 {
374  KHTMLPart *rootPart = part;
375  while (rootPart->parentPart()) {
376  rootPart = rootPart->parentPart();
377  }
378  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle());
379  QPaintDevice *pd = doc->paintDevice();
380  bool printing = pd ? (pd->devType() == QInternal::Printer) : false;
381  unsigned int numColors = 0;
382  if (printing) {
383  numColors = pd->colorCount();
384  } else {
385  int sn = QApplication::desktop()->screenNumber(rootPart->view());
386  numColors = QApplication::desktop()->screen(sn)->colorCount();
387  }
388  if (numColors == INT_MAX) {
389  numColors = UINT_MAX;
390  }
391  if (value) {
392  float number = 0;
393  return numberValue(value, number) && compareValue(numColors, static_cast<unsigned int>(number), op);
394  }
395 
396  return numColors;
397 }
398 
399 static bool colorMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op)
400 {
401  KHTMLPart *rootPart = part;
402  while (rootPart->parentPart()) {
403  rootPart = rootPart->parentPart();
404  }
405  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle());
406  QPaintDevice *pd = doc->paintDevice();
407  bool printing = pd ? (pd->devType() == QInternal::Printer) : false;
408  int bitsPerComponent = 0;
409  if (printing) {
410  if (pd->colorCount() > 2) {
411  bitsPerComponent = pd->depth() / 3;
412  }
413  // assume printer is either b&w or color.
414  } else {
415  int sn = QApplication::desktop()->screenNumber(rootPart->view());
417  bitsPerComponent = QApplication::desktop()->screen(sn)->depth() / 3;
418  }
419  }
420  if (value && bitsPerComponent) {
421  float number = 0;
422  return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op);
423  }
424  return bitsPerComponent;
425 }
426 
427 static bool monochromeMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op)
428 {
429  KHTMLPart *rootPart = part;
430  while (rootPart->parentPart()) {
431  rootPart = rootPart->parentPart();
432  }
433  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle());
434  QPaintDevice *pd = doc->paintDevice();
435  bool printing = pd ? (pd->devType() == QInternal::Printer) : false;
436  int depth = 0;
437  if (printing) {
438  if (pd->colorCount() < 2) {
439  depth = 1;
440  }
441  // assume printer is either b&w or color.
442  } else {
443  int sn = QApplication::desktop()->screenNumber(rootPart->view());
444  if (QApplication::desktop()->screen(sn)->depth() == 1) {
445  depth = 1;
446  } else if (QColormap::instance(sn).mode() == QColormap::Gray) {
447  depth = QApplication::desktop()->screen(sn)->depth();
448  }
449  }
450  if (value) {
451  float number = 0;
452  return numberValue(value, number) && compareValue(depth, static_cast<int>(number), op);
453  }
454  return depth;
455 }
456 
457 static bool device_aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op)
458 {
459  if (value) {
460  KHTMLPart *rootPart = part;
461  while (rootPart->parentPart()) {
462  rootPart = rootPart->parentPart();
463  }
464  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle());
465  QPaintDevice *pd = doc->paintDevice();
466  bool printing = pd ? (pd->devType() == QInternal::Printer) : false;
467  QRect sg;
468  int h = 0, v = 0;
469  if (printing) {
470  sg = QRect(0, 0, pd->width(), pd->height());
471  } else {
472  sg = QApplication::desktop()->screen(QApplication::desktop()->screenNumber(rootPart->view()))->rect();
473  }
474  if (parseAspectRatio(value, h, v)) {
475  return v != 0 && compareValue(sg.width() * v, sg.height() * h, op);
476  }
477  return false;
478  }
479 
480  // ({,min-,max-}device-aspect-ratio)
481  // assume if we have a device, its aspect ratio is non-zero
482  return true;
483 }
484 
485 static bool aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op)
486 {
487  if (value) {
488  KHTMLPart *rootPart = part;
489  while (rootPart->parentPart()) {
490  rootPart = rootPart->parentPart();
491  }
492  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle());
493  QPaintDevice *pd = doc->paintDevice();
494  bool printing = pd ? (pd->devType() == QInternal::Printer) : false;
495  QSize vs;
496  int h = 0, v = 0;
497  if (printing) {
498  vs = QSize(pd->width(), pd->height());
499  } else {
500  vs = QSize(part->view()->visibleWidth(), part->view()->visibleHeight());
501  }
502  if (parseAspectRatio(value, h, v)) {
503  return v != 0 && compareValue(vs.width() * v, vs.height() * h, op);
504  }
505  return false;
506  }
507  // ({,min-,max-}aspect-ratio)
508  // assume if we have a viewport, its aspect ratio is non-zero
509  return true;
510 }
511 
512 static bool orientationMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix /*op*/)
513 {
514  if (value) {
515  CSSPrimitiveValueImpl *pv = static_cast<CSSPrimitiveValueImpl *>(value);
516  if (!value->isPrimitiveValue() || pv->primitiveType() != CSSPrimitiveValue::CSS_IDENT ||
517  (pv->getIdent() != CSS_VAL_PORTRAIT && pv->getIdent() != CSS_VAL_LANDSCAPE)) {
518  return false;
519  }
520 
521  KHTMLPart *rootPart = part;
522  while (rootPart->parentPart()) {
523  rootPart = rootPart->parentPart();
524  }
525  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle());
526  QPaintDevice *pd = doc->paintDevice();
527  bool printing = pd ? (pd->devType() == QInternal::Printer) : false;
528  if (printing) {
529  if (pd->width() > pd->height()) {
530  return (pv->getIdent() == CSS_VAL_LANDSCAPE);
531  }
532  } else {
533  if (part->view()->visibleWidth() > part->view()->visibleHeight()) {
534  return (pv->getIdent() == CSS_VAL_LANDSCAPE);
535  }
536  }
537  return (pv->getIdent() == CSS_VAL_PORTRAIT);
538  }
539  return false;
540 }
541 
542 static bool device_pixel_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op)
543 {
544  if (value) {
545  return value->isPrimitiveValue() && compareValue(part->zoomFactor() / 100.0, static_cast<CSSPrimitiveValueImpl *>(value)->floatValue(), op);
546  }
547 
548  return part->zoomFactor() != 0;
549 }
550 
551 static bool gridMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart * /*part*/, MediaFeaturePrefix op)
552 {
553  // if output device is bitmap, grid: 0 == true
554  // assume we have bitmap device
555  float number;
556  if (value && numberValue(value, number)) {
557  return compareValue(static_cast<int>(number), 0, op);
558  }
559  return false;
560 }
561 
562 // for printing media, we'll make the approximation that the device height == the paged box's height
563 static bool device_heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix op)
564 {
565  if (value) {
566  KHTMLPart *rootPart = part;
567  while (rootPart->parentPart()) {
568  rootPart = rootPart->parentPart();
569  }
570  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle());
571  QPaintDevice *pd = doc->paintDevice();
572  bool printing = pd ? (pd->devType() == QInternal::Printer) : false;
573  int height;
574  if (printing) {
575  height = pd->height();
576  } else {
577  height = QApplication::desktop()->screen(QApplication::desktop()->screenNumber(rootPart->view()))->rect().height();
578  doc = static_cast<DOM::DocumentImpl *>(part->document().handle());
579  }
580  int logicalDpiY = doc->logicalDpiY();
581  return value->isPrimitiveValue() && compareValue(height, static_cast<CSSPrimitiveValueImpl *>(value)->computeLength(style, style, logicalDpiY), op);
582  }
583  // ({,min-,max-}device-height)
584  // assume if we have a device, assume non-zero
585  return true;
586 }
587 
588 static bool device_widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix op)
589 {
590  if (value) {
591  KHTMLPart *rootPart = part;
592  while (rootPart->parentPart()) {
593  rootPart = rootPart->parentPart();
594  }
595  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle());
596  QPaintDevice *pd = doc->paintDevice();
597  bool printing = pd ? (pd->devType() == QInternal::Printer) : false;
598  int width;
599  if (printing) {
600  width = pd->width();
601  } else {
602  width = QApplication::desktop()->screen(QApplication::desktop()->screenNumber(rootPart->view()))->rect().width();
603  doc = static_cast<DOM::DocumentImpl *>(part->document().handle());
604  }
605  int logicalDpiY = doc->logicalDpiY();
606  return value->isPrimitiveValue() && compareValue(width, static_cast<CSSPrimitiveValueImpl *>(value)->computeLength(style, style, logicalDpiY), op);
607  }
608  // ({,min-,max-}device-width)
609  // assume if we have a device, assume non-zero
610  return true;
611 }
612 
613 // cf. https://www.w3.org/TR/css3-mediaqueries/#device-width
614 // "For continuous media, this is the width of the viewport (as described by CSS2, section 9.1.1 [CSS2]).
615 // For paged media, this is the width of the page box (as described by CSS2, section 13.2 [CSS2])"
616 
617 static bool widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix op)
618 {
619  KHTMLPart *rootPart = part;
620  while (rootPart->parentPart()) {
621  rootPart = rootPart->parentPart();
622  }
623  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle());
624  QPaintDevice *pd = doc->paintDevice();
625  bool printing = pd ? (pd->devType() == QInternal::Printer) : false;
626  int width;
627  if (printing) {
628  width = pd->width();
629  } else {
630  width = part->view()->visibleWidth();
631  doc = static_cast<DOM::DocumentImpl *>(part->document().handle());
632  }
633  int logicalDpiY = doc->logicalDpiY();
634  if (value) {
635  return value->isPrimitiveValue() && compareValue(width, static_cast<CSSPrimitiveValueImpl *>(value)->computeLength(style, style, logicalDpiY), op);
636  }
637 
638  return width > 0;
639 }
640 
641 static bool heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix op)
642 {
643  KHTMLPart *rootPart = part;
644  while (rootPart->parentPart()) {
645  rootPart = rootPart->parentPart();
646  }
647  DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl *>(rootPart->document().handle());
648  QPaintDevice *pd = doc->paintDevice();
649  bool printing = pd ? (pd->devType() == QInternal::Printer) : false;
650  int height;
651  if (printing) {
652  height = pd->height();
653  } else {
654  height = part->view()->visibleHeight();
655  doc = static_cast<DOM::DocumentImpl *>(part->document().handle());
656  }
657  int logicalDpiY = doc->logicalDpiY();
658  if (value) {
659  return value->isPrimitiveValue() && compareValue(height, static_cast<CSSPrimitiveValueImpl *>(value)->computeLength(style, style, logicalDpiY), op);
660  }
661 
662  return height > 0;
663 }
664 
665 static bool resolutionMediaFeatureEval(CSSValueImpl *value, RenderStyle *, KHTMLPart *part, MediaFeaturePrefix op)
666 {
667  DOM::DocumentImpl *d = static_cast<DOM::DocumentImpl *>(part->document().handle());
668  int logicalDpiY = d ? d->logicalDpiY() : 0;
669 
670  if (value && logicalDpiY) {
671  return value->isPrimitiveValue() && compareValue(logicalDpiY, static_cast<CSSPrimitiveValueImpl *>(value)->getDPIResolution(), op);
672  }
673 
674  return logicalDpiY != 0;
675 }
676 
677 static bool scanMediaFeatureEval(CSSValueImpl * /*value*/, RenderStyle *, KHTMLPart * /*part*/, MediaFeaturePrefix)
678 {
679  // no support for tv media type.
680  return false;
681 }
682 
683 // rest of the functions are trampolines which set the prefix according to the media feature expression used
684 
685 static bool min_color_indexMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
686 {
687  return color_indexMediaFeatureEval(value, style, part, MinPrefix);
688 }
689 
690 static bool max_color_indexMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
691 {
692  return color_indexMediaFeatureEval(value, style, part, MinPrefix);
693 }
694 
695 static bool min_colorMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
696 {
697  return colorMediaFeatureEval(value, style, part, MinPrefix);
698 }
699 
700 static bool max_colorMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
701 {
702  return colorMediaFeatureEval(value, style, part, MaxPrefix);
703 }
704 
705 static bool min_monochromeMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
706 {
707  return monochromeMediaFeatureEval(value, style, part, MinPrefix);
708 }
709 
710 static bool max_monochromeMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
711 {
712  return monochromeMediaFeatureEval(value, style, part, MaxPrefix);
713 }
714 
715 static bool min_device_aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
716 {
717  return device_aspect_ratioMediaFeatureEval(value, style, part, MinPrefix);
718 }
719 
720 static bool max_device_aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
721 {
722  return device_aspect_ratioMediaFeatureEval(value, style, part, MaxPrefix);
723 }
724 
725 static bool min_aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
726 {
727  return aspect_ratioMediaFeatureEval(value, style, part, MinPrefix);
728 }
729 
730 static bool max_aspect_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
731 {
732  return aspect_ratioMediaFeatureEval(value, style, part, MaxPrefix);
733 }
734 
735 static bool min_device_pixel_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
736 {
737  return device_pixel_ratioMediaFeatureEval(value, style, part, MinPrefix);
738 }
739 
740 static bool max_device_pixel_ratioMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
741 {
742  return device_pixel_ratioMediaFeatureEval(value, style, part, MaxPrefix);
743 }
744 
745 static bool min_heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
746 {
747  return heightMediaFeatureEval(value, style, part, MinPrefix);
748 }
749 
750 static bool max_heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
751 {
752  return heightMediaFeatureEval(value, style, part, MaxPrefix);
753 }
754 
755 static bool min_widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
756 {
757  return widthMediaFeatureEval(value, style, part, MinPrefix);
758 }
759 
760 static bool max_widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
761 {
762  return widthMediaFeatureEval(value, style, part, MaxPrefix);
763 }
764 
765 static bool min_device_heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
766 {
767  return device_heightMediaFeatureEval(value, style, part, MinPrefix);
768 }
769 
770 static bool max_device_heightMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
771 {
772  return device_heightMediaFeatureEval(value, style, part, MaxPrefix);
773 }
774 
775 static bool min_device_widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
776 {
777  return device_widthMediaFeatureEval(value, style, part, MinPrefix);
778 }
779 
780 static bool max_device_widthMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
781 {
782  return device_widthMediaFeatureEval(value, style, part, MaxPrefix);
783 }
784 
785 static bool min_resolutionMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
786 {
787  return resolutionMediaFeatureEval(value, style, part, MinPrefix);
788 }
789 
790 static bool max_resolutionMediaFeatureEval(CSSValueImpl *value, RenderStyle *style, KHTMLPart *part, MediaFeaturePrefix /*op*/)
791 {
792  return resolutionMediaFeatureEval(value, style, part, MaxPrefix);
793 }
794 
795 static void createFunctionMap()
796 {
797  // Create the table.
798  gFunctionMap = new FunctionMap;
799 #define ADD_TO_FUNCTIONMAP(name, str) \
800  gFunctionMap->insert(DOMString(str), name##MediaFeatureEval);
801  CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP);
802 #undef ADD_TO_FUNCTIONMAP
803 }
804 
805 void MediaQueryEvaluator::cleanup() // static
806 {
807  delete gFunctionMap;
808  gFunctionMap = nullptr;
809 }
810 
811 bool MediaQueryEvaluator::eval(const MediaQueryExp *expr) const
812 {
813  if (!m_part || !m_style) {
814  return m_expResult;
815  }
816 
817  if (!gFunctionMap) {
818  createFunctionMap();
819  }
820 
821  // call the media feature evaluation function. Assume no prefix
822  // and let trampoline functions override the prefix if prefix is
823  // used
824  FunctionMap::ConstIterator func = gFunctionMap->constFind(expr->mediaFeature());
825  if (func != gFunctionMap->constEnd()) {
826  return (*func.value())(expr->value(), m_style, m_part, NoPrefix);
827  }
828 
829  return false;
830 }
int colorCount() const const
QWidget * screen(int screen)
This file is part of the HTML rendering engine for KDE.
const T & at(int i) const const
This class is khtml&#39;s main class.
Definition: khtml_part.h:208
QHash::const_iterator constFind(const Key &key) const const
int screenNumber(const QWidget *widget) const const
int size() const const
int width() const const
KHTMLView * view() const
Returns a pointer to the HTML document&#39;s view.
int visibleWidth() const
Returns the width of the viewport.
Definition: khtmlview.cpp:719
int visibleHeight() const
Returns the height of the viewport.
Definition: khtmlview.cpp:735
QColormap::Mode mode() const const
QHash::const_iterator constEnd() const const
bool eval(const DOM::MediaListImpl *, CSSStyleSelector *=nullptr) const
Evaluates a list of media queries.
UnitTypes
An integer indicating which type of unit applies to the value.
Definition: css_value.h:384
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
MediaQueryEvaluator(bool mediaFeatureResult=false)
Creates evaluator which evaluates only simple media queries Evaluator returns true for "all"...
the StyleSelector implementation for CSS.
typedef ConstIterator
This library provides a full-featured HTML parser and widget.
QDesktopWidget * desktop()
bool isValid(QStringView ifopt)
QColormap instance(int screen)
int zoomFactor() const
Returns the current zoom factor.
DOM::Document document() const
Returns a reference to the DOM document.
int height() const const
NodeImpl * handle() const
Definition: dom_node.h:936
int depth() const const
KHTMLPart * parentPart()
Returns a pointer to the parent KHTMLPart if the part is a frame in an HTML frameset.
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Oct 24 2021 22:47:58 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.