12949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project/* 22949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * CSS Media Query Evaluator 32949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * 42949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * Copyright (C) 2006 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>. 52949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * 62949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * Redistribution and use in source and binary forms, with or without 72949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * modification, are permitted provided that the following conditions 82949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * are met: 92949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * 1. Redistributions of source code must retain the above copyright 102949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * notice, this list of conditions and the following disclaimer. 112949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright 122949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * notice, this list of conditions and the following disclaimer in the 132949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * documentation and/or other materials provided with the distribution. 142949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * 152949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 162949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 172949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 182949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 192949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 202949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 212949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 222949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 232949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 242949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 252949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 262949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project */ 272949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 282949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "config.h" 292949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "MediaQueryEvaluator.h" 302949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 312949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "Chrome.h" 322949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "ChromeClient.h" 332949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "CSSPrimitiveValue.h" 342949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "CSSStyleSelector.h" 352949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "CSSValueList.h" 362949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "FloatRect.h" 372949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "Frame.h" 382949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "FrameView.h" 392949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "IntRect.h" 402949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "MediaFeatureNames.h" 412949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "MediaList.h" 422949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "MediaQuery.h" 432949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "MediaQueryExp.h" 442949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "NodeRenderStyle.h" 452949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "Page.h" 462949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "RenderView.h" 472949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "RenderStyle.h" 482949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "PlatformScreen.h" 492949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include <wtf/HashMap.h> 502949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 512949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#if ENABLE(3D_RENDERING) && USE(ACCELERATED_COMPOSITING) 522949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#include "RenderLayerCompositor.h" 532949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project#endif 542949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 552949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectnamespace WebCore { 562949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 572949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectusing namespace MediaFeatureNames; 582949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 592949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectenum MediaFeaturePrefix { MinPrefix, MaxPrefix, NoPrefix }; 602949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 612949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projecttypedef bool (*EvalFunc)(CSSValue*, RenderStyle*, Frame*, MediaFeaturePrefix); 622949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projecttypedef HashMap<AtomicStringImpl*, EvalFunc> FunctionMap; 632949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectstatic FunctionMap* gFunctionMap; 642949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 652949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project/* 662949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * FIXME: following media features are not implemented: color_index, scan, resolution 672949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * 682949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * color_index, min-color-index, max_color_index: It's unknown how to retrieve 692949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * the information if the display mode is indexed 702949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * scan: The "scan" media feature describes the scanning process of 712949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * tv output devices. It's unknown how to retrieve this information from 722949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * the platform 732949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * resolution, min-resolution, max-resolution: css parser doesn't seem to 742949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project * support CSS_DIMENSION 752949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project */ 762949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 772949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source ProjectMediaQueryEvaluator::MediaQueryEvaluator(bool mediaFeatureResult) 782949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project : m_frame(0) 792949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project , m_style(0) 802949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project , m_expResult(mediaFeatureResult) 812949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{ 822949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project} 832949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 842949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source ProjectMediaQueryEvaluator:: MediaQueryEvaluator(const String& acceptedMediaType, bool mediaFeatureResult) 852949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project : m_mediaType(acceptedMediaType) 862949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project , m_frame(0) 872949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project , m_style(0) 882949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project , m_expResult(mediaFeatureResult) 892949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{ 902949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project} 912949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 922949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source ProjectMediaQueryEvaluator:: MediaQueryEvaluator(const char* acceptedMediaType, bool mediaFeatureResult) 932949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project : m_mediaType(acceptedMediaType) 942949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project , m_frame(0) 952949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project , m_style(0) 962949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project , m_expResult(mediaFeatureResult) 972949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{ 982949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project} 992949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 1002949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source ProjectMediaQueryEvaluator:: MediaQueryEvaluator(const String& acceptedMediaType, Frame* frame, RenderStyle* style) 1012949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project : m_mediaType(acceptedMediaType) 1022949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project , m_frame(frame) 1032949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project , m_style(style) 1042949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project , m_expResult(false) // doesn't matter when we have m_frame and m_style 1052949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{ 1062949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project} 1072949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 1082949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source ProjectMediaQueryEvaluator::~MediaQueryEvaluator() 1092949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{ 1102949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project} 1112949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 1122949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectbool MediaQueryEvaluator::mediaTypeMatch(const String& mediaTypeToMatch) const 1132949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{ 1142949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project return mediaTypeToMatch.isEmpty() 1152949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project || equalIgnoringCase(mediaTypeToMatch, "all") 1162949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project || equalIgnoringCase(mediaTypeToMatch, m_mediaType); 1172949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project} 1182949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 1192949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Projectbool MediaQueryEvaluator::mediaTypeMatchSpecific(const char* mediaTypeToMatch) const 1202949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project{ 1212949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project // Like mediaTypeMatch, but without the special cases for "" and "all". 1222949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project ASSERT(mediaTypeToMatch); 1232949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project ASSERT(mediaTypeToMatch[0] != '\0'); 1242949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project ASSERT(!equalIgnoringCase(mediaTypeToMatch, String("all"))); 1252949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project return equalIgnoringCase(mediaTypeToMatch, m_mediaType); 1262949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project} 1272949f58a438f6fd85f66a8b7ed4708042cde4b37The Android Open Source Project 128static bool applyRestrictor(MediaQuery::Restrictor r, bool value) 129{ 130 return r == MediaQuery::Not ? !value : value; 131} 132 133bool MediaQueryEvaluator::eval(const MediaList* mediaList, CSSStyleSelector* styleSelector) const 134{ 135 if (!mediaList) 136 return true; 137 138 const Vector<MediaQuery*>& queries = mediaList->mediaQueries(); 139 if (!queries.size()) 140 return true; // empty query list evaluates to true 141 142 // iterate over queries, stop if any of them eval to true (OR semantics) 143 bool result = false; 144 for (size_t i = 0; i < queries.size() && !result; ++i) { 145 MediaQuery* query = queries.at(i); 146 147 if (query->ignored()) 148 continue; 149 150 if (mediaTypeMatch(query->mediaType())) { 151 const Vector<OwnPtr<MediaQueryExp> >* exps = query->expressions(); 152 // iterate through expressions, stop if any of them eval to false 153 // (AND semantics) 154 size_t j = 0; 155 for (; j < exps->size(); ++j) { 156 bool exprResult = eval(exps->at(j).get()); 157 if (styleSelector && exps->at(j)->isViewportDependent()) 158 styleSelector->addViewportDependentMediaQueryResult(exps->at(j).get(), exprResult); 159 if (!exprResult) 160 break; 161 } 162 163 // assume true if we are at the end of the list, 164 // otherwise assume false 165 result = applyRestrictor(query->restrictor(), exps->size() == j); 166 } else 167 result = applyRestrictor(query->restrictor(), false); 168 } 169 170 return result; 171} 172 173static bool parseAspectRatio(CSSValue* value, int& h, int& v) 174{ 175 if (value->isValueList()) { 176 CSSValueList* valueList = static_cast<CSSValueList*>(value); 177 if (valueList->length() == 3) { 178 CSSValue* i0 = valueList->itemWithoutBoundsCheck(0); 179 CSSValue* i1 = valueList->itemWithoutBoundsCheck(1); 180 CSSValue* i2 = valueList->itemWithoutBoundsCheck(2); 181 if (i0->isPrimitiveValue() && static_cast<CSSPrimitiveValue*>(i0)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER 182 && i1->isPrimitiveValue() && static_cast<CSSPrimitiveValue*>(i1)->primitiveType() == CSSPrimitiveValue::CSS_STRING 183 && i2->isPrimitiveValue() && static_cast<CSSPrimitiveValue*>(i2)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) { 184 String str = static_cast<CSSPrimitiveValue*>(i1)->getStringValue(); 185 if (!str.isNull() && str.length() == 1 && str[0] == '/') { 186 h = static_cast<CSSPrimitiveValue*>(i0)->getIntValue(CSSPrimitiveValue::CSS_NUMBER); 187 v = static_cast<CSSPrimitiveValue*>(i2)->getIntValue(CSSPrimitiveValue::CSS_NUMBER); 188 return true; 189 } 190 } 191 } 192 } 193 return false; 194} 195 196template<typename T> 197bool compareValue(T a, T b, MediaFeaturePrefix op) 198{ 199 switch (op) { 200 case MinPrefix: 201 return a >= b; 202 case MaxPrefix: 203 return a <= b; 204 case NoPrefix: 205 return a == b; 206 } 207 return false; 208} 209 210static bool numberValue(CSSValue* value, float& result) 211{ 212 if (value->isPrimitiveValue() 213 && static_cast<CSSPrimitiveValue*>(value)->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) { 214 result = static_cast<CSSPrimitiveValue*>(value)->getFloatValue(CSSPrimitiveValue::CSS_NUMBER); 215 return true; 216 } 217 return false; 218} 219 220static bool colorMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 221{ 222 int bitsPerComponent = screenDepthPerComponent(frame->page()->mainFrame()->view()); 223 float number; 224 if (value) 225 return numberValue(value, number) && compareValue(bitsPerComponent, static_cast<int>(number), op); 226 227 return bitsPerComponent != 0; 228} 229 230static bool monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) 231{ 232 if (!screenIsMonochrome(frame->page()->mainFrame()->view())) { 233 if (value) { 234 float number; 235 return numberValue(value, number) && compareValue(0, static_cast<int>(number), op); 236 } 237 return false; 238 } 239 240 return colorMediaFeatureEval(value, style, frame, op); 241} 242 243static bool orientationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix) 244{ 245 // A missing parameter should fail 246 if (!value) 247 return false; 248 249 FrameView* view = frame->view(); 250 int width = view->layoutWidth(); 251 int height = view->layoutHeight(); 252 if (width > height) // Square viewport is portrait 253 return "landscape" == static_cast<CSSPrimitiveValue*>(value)->getStringValue(); 254 return "portrait" == static_cast<CSSPrimitiveValue*>(value)->getStringValue(); 255} 256 257static bool aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 258{ 259 if (value) { 260 FrameView* view = frame->view(); 261 int width = view->layoutWidth(); 262 int height = view->layoutHeight(); 263 int h = 0; 264 int v = 0; 265 if (parseAspectRatio(value, h, v)) 266 return v != 0 && compareValue(width * v, height * h, op); 267 return false; 268 } 269 270 // ({,min-,max-}aspect-ratio) 271 // assume if we have a device, its aspect ratio is non-zero 272 return true; 273} 274 275static bool device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 276{ 277 if (value) { 278 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); 279 int h = 0; 280 int v = 0; 281 if (parseAspectRatio(value, h, v)) 282 return v != 0 && compareValue(static_cast<int>(sg.width()) * v, static_cast<int>(sg.height()) * h, op); 283 return false; 284 } 285 286 // ({,min-,max-}device-aspect-ratio) 287 // assume if we have a device, its aspect ratio is non-zero 288 return true; 289} 290 291static bool device_pixel_ratioMediaFeatureEval(CSSValue *value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 292{ 293 if (value) 294 return value->isPrimitiveValue() && compareValue(frame->page()->chrome()->scaleFactor(), static_cast<CSSPrimitiveValue*>(value)->getFloatValue(), op); 295 296 return frame->page()->chrome()->scaleFactor() != 0; 297} 298 299static bool gridMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) 300{ 301 // if output device is bitmap, grid: 0 == true 302 // assume we have bitmap device 303 float number; 304 if (value && numberValue(value, number)) 305 return compareValue(static_cast<int>(number), 0, op); 306 return false; 307} 308 309static bool device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) 310{ 311 if (value) { 312 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); 313 RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); 314 return value->isPrimitiveValue() && compareValue(static_cast<int>(sg.height()), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op); 315 } 316 // ({,min-,max-}device-height) 317 // assume if we have a device, assume non-zero 318 return true; 319} 320 321static bool device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) 322{ 323 if (value) { 324 FloatRect sg = screenRect(frame->page()->mainFrame()->view()); 325 RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); 326 return value->isPrimitiveValue() && compareValue(static_cast<int>(sg.width()), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op); 327 } 328 // ({,min-,max-}device-width) 329 // assume if we have a device, assume non-zero 330 return true; 331} 332 333static bool heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) 334{ 335 FrameView* view = frame->view(); 336 RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); 337 338 if (value) 339 return value->isPrimitiveValue() && compareValue(view->layoutHeight(), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op); 340 341 return view->layoutHeight() != 0; 342} 343 344static bool widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix op) 345{ 346 FrameView* view = frame->view(); 347 RenderStyle* rootStyle = frame->document()->documentElement()->renderStyle(); 348 349 if (value) 350 return value->isPrimitiveValue() && compareValue(view->layoutWidth(), static_cast<CSSPrimitiveValue*>(value)->computeLengthInt(style, rootStyle), op); 351 352 return view->layoutWidth() != 0; 353} 354 355// rest of the functions are trampolines which set the prefix according to the media feature expression used 356 357static bool min_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 358{ 359 return colorMediaFeatureEval(value, style, frame, MinPrefix); 360} 361 362static bool max_colorMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 363{ 364 return colorMediaFeatureEval(value, style, frame, MaxPrefix); 365} 366 367static bool min_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 368{ 369 return monochromeMediaFeatureEval(value, style, frame, MinPrefix); 370} 371 372static bool max_monochromeMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 373{ 374 return monochromeMediaFeatureEval(value, style, frame, MaxPrefix); 375} 376 377static bool min_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 378{ 379 return aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); 380} 381 382static bool max_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 383{ 384 return aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); 385} 386 387static bool min_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 388{ 389 return device_aspect_ratioMediaFeatureEval(value, style, frame, MinPrefix); 390} 391 392static bool max_device_aspect_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 393{ 394 return device_aspect_ratioMediaFeatureEval(value, style, frame, MaxPrefix); 395} 396 397static bool min_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 398{ 399 return device_pixel_ratioMediaFeatureEval(value, style, frame, MinPrefix); 400} 401 402static bool max_device_pixel_ratioMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 403{ 404 return device_pixel_ratioMediaFeatureEval(value, style, frame, MaxPrefix); 405} 406 407static bool min_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 408{ 409 return heightMediaFeatureEval(value, style, frame, MinPrefix); 410} 411 412static bool max_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 413{ 414 return heightMediaFeatureEval(value, style, frame, MaxPrefix); 415} 416 417static bool min_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 418{ 419 return widthMediaFeatureEval(value, style, frame, MinPrefix); 420} 421 422static bool max_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 423{ 424 return widthMediaFeatureEval(value, style, frame, MaxPrefix); 425} 426 427static bool min_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 428{ 429 return device_heightMediaFeatureEval(value, style, frame, MinPrefix); 430} 431 432static bool max_device_heightMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 433{ 434 return device_heightMediaFeatureEval(value, style, frame, MaxPrefix); 435} 436 437static bool min_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 438{ 439 return device_widthMediaFeatureEval(value, style, frame, MinPrefix); 440} 441 442static bool max_device_widthMediaFeatureEval(CSSValue* value, RenderStyle* style, Frame* frame, MediaFeaturePrefix) 443{ 444 return device_widthMediaFeatureEval(value, style, frame, MaxPrefix); 445} 446 447static bool animationMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) 448{ 449 if (value) { 450 float number; 451 return numberValue(value, number) && compareValue(1, static_cast<int>(number), op); 452 } 453 return true; 454} 455 456static bool transitionMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) 457{ 458 if (value) { 459 float number; 460 return numberValue(value, number) && compareValue(1, static_cast<int>(number), op); 461 } 462 return true; 463} 464 465static bool transform_2dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame*, MediaFeaturePrefix op) 466{ 467 if (value) { 468 float number; 469 return numberValue(value, number) && compareValue(1, static_cast<int>(number), op); 470 } 471 return true; 472} 473 474static bool transform_3dMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 475{ 476 bool returnValueIfNoParameter; 477 int have3dRendering; 478 479#if ENABLE(3D_RENDERING) 480 bool threeDEnabled = false; 481#if USE(ACCELERATED_COMPOSITING) 482 if (RenderView* view = frame->contentRenderer()) 483 threeDEnabled = view->compositor()->canRender3DTransforms(); 484#endif 485 486 returnValueIfNoParameter = threeDEnabled; 487 have3dRendering = threeDEnabled ? 1 : 0; 488#else 489 UNUSED_PARAM(frame); 490 returnValueIfNoParameter = false; 491 have3dRendering = 0; 492#endif 493 494 if (value) { 495 float number; 496 return numberValue(value, number) && compareValue(have3dRendering, static_cast<int>(number), op); 497 } 498 return returnValueIfNoParameter; 499} 500 501static bool view_modeMediaFeatureEval(CSSValue* value, RenderStyle*, Frame* frame, MediaFeaturePrefix op) 502{ 503 UNUSED_PARAM(op); 504 if (!value) 505 return true; 506 return Page::stringToViewMode(static_cast<CSSPrimitiveValue*>(value)->getStringValue()) == frame->page()->viewMode(); 507} 508 509static void createFunctionMap() 510{ 511 // Create the table. 512 gFunctionMap = new FunctionMap; 513#define ADD_TO_FUNCTIONMAP(name, str) \ 514 gFunctionMap->set(name##MediaFeature.impl(), name##MediaFeatureEval); 515 CSS_MEDIAQUERY_NAMES_FOR_EACH_MEDIAFEATURE(ADD_TO_FUNCTIONMAP); 516#undef ADD_TO_FUNCTIONMAP 517} 518 519bool MediaQueryEvaluator::eval(const MediaQueryExp* expr) const 520{ 521 if (!m_frame || !m_style) 522 return m_expResult; 523 524 if (!expr->isValid()) 525 return false; 526 527 if (!gFunctionMap) 528 createFunctionMap(); 529 530 // call the media feature evaluation function. Assume no prefix 531 // and let trampoline functions override the prefix if prefix is 532 // used 533 EvalFunc func = gFunctionMap->get(expr->mediaFeature().impl()); 534 if (func) 535 return func(expr->value(), m_style, m_frame, NoPrefix); 536 537 return false; 538} 539 540} // namespace 541