Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp

Issue 1474513003: Upgrade PixelStorei to ES3/WebGL2. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "config.h" 5 #include "config.h"
6 #include "modules/webgl/WebGL2RenderingContextBase.h" 6 #include "modules/webgl/WebGL2RenderingContextBase.h"
7 7
8 #include "bindings/modules/v8/WebGLAny.h" 8 #include "bindings/modules/v8/WebGLAny.h"
9 #include "core/html/HTMLCanvasElement.h" 9 #include "core/html/HTMLCanvasElement.h"
10 #include "core/html/HTMLImageElement.h" 10 #include "core/html/HTMLImageElement.h"
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 webContext()->getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &maxTr ansformFeedbackSeparateAttribs); 156 webContext()->getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &maxTr ansformFeedbackSeparateAttribs);
157 m_boundIndexedTransformFeedbackBuffers.clear(); 157 m_boundIndexedTransformFeedbackBuffers.clear();
158 m_boundIndexedTransformFeedbackBuffers.resize(maxTransformFeedbackSeparateAt tribs); 158 m_boundIndexedTransformFeedbackBuffers.resize(maxTransformFeedbackSeparateAt tribs);
159 159
160 GLint maxUniformBufferBindings = 0; 160 GLint maxUniformBufferBindings = 0;
161 webContext()->getIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferB indings); 161 webContext()->getIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferB indings);
162 m_boundIndexedUniformBuffers.clear(); 162 m_boundIndexedUniformBuffers.clear();
163 m_boundIndexedUniformBuffers.resize(maxUniformBufferBindings); 163 m_boundIndexedUniformBuffers.resize(maxUniformBufferBindings);
164 m_maxBoundUniformBufferIndex = 0; 164 m_maxBoundUniformBufferIndex = 0;
165 165
166 m_packRowLength = 0;
167 m_packSkipPixels = 0;
168 m_packSkipRows = 0;
169 m_unpackRowLength = 0;
170 m_unpackImageHeight = 0;
171 m_unpackSkipPixels = 0;
172 m_unpackSkipRows = 0;
173 m_unpackSkipImages = 0;
174
166 WebGLRenderingContextBase::initializeNewContext(); 175 WebGLRenderingContextBase::initializeNewContext();
167 } 176 }
168 177
169 void WebGL2RenderingContextBase::copyBufferSubData(GLenum readTarget, GLenum wri teTarget, long long readOffset, long long writeOffset, long long size) 178 void WebGL2RenderingContextBase::copyBufferSubData(GLenum readTarget, GLenum wri teTarget, long long readOffset, long long writeOffset, long long size)
170 { 179 {
171 if (isContextLost()) 180 if (isContextLost())
172 return; 181 return;
173 182
174 if (!validateValueFitNonNegInt32("copyBufferSubData", "readOffset", readOffs et) 183 if (!validateValueFitNonNegInt32("copyBufferSubData", "readOffset", readOffs et)
175 || !validateValueFitNonNegInt32("copyBufferSubData", "writeOffset", writ eOffset) 184 || !validateValueFitNonNegInt32("copyBufferSubData", "writeOffset", writ eOffset)
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
442 } else { 451 } else {
443 if (mode == GL_BACK) { 452 if (mode == GL_BACK) {
444 synthesizeGLError(GL_INVALID_OPERATION, "readBuffer", "invalid read buffer"); 453 synthesizeGLError(GL_INVALID_OPERATION, "readBuffer", "invalid read buffer");
445 return; 454 return;
446 } 455 }
447 readFramebufferBinding->readBuffer(mode); 456 readFramebufferBinding->readBuffer(mode);
448 } 457 }
449 webContext()->readBuffer(mode); 458 webContext()->readBuffer(mode);
450 } 459 }
451 460
461 void WebGL2RenderingContextBase::pixelStorei(GLenum pname, GLint param)
462 {
463 if (isContextLost())
464 return;
465 switch (pname) {
466 case GL_PACK_ROW_LENGTH:
467 m_packRowLength = param;
468 break;
469 case GL_PACK_SKIP_PIXELS:
470 m_packSkipPixels = param;
471 break;
472 case GL_PACK_SKIP_ROWS:
473 m_packSkipRows = param;
474 break;
475 case GL_UNPACK_ROW_LENGTH:
476 m_unpackRowLength = param;
477 break;
478 case GL_UNPACK_IMAGE_HEIGHT:
479 m_unpackImageHeight = param;
480 break;
481 case GL_UNPACK_SKIP_PIXELS:
482 m_unpackSkipPixels = param;
483 break;
484 case GL_UNPACK_SKIP_ROWS:
485 m_unpackSkipRows = param;
486 break;
487 case GL_UNPACK_SKIP_IMAGES:
488 m_unpackSkipImages = param;
489 break;
490 default:
491 WebGLRenderingContextBase::pixelStorei(pname, param);
492 return;
493 }
494 webContext()->pixelStorei(pname, param);
495 }
496
452 void WebGL2RenderingContextBase::readPixels(GLint x, GLint y, GLsizei width, GLs izei height, GLenum format, GLenum type, DOMArrayBufferView* pixels) 497 void WebGL2RenderingContextBase::readPixels(GLint x, GLint y, GLsizei width, GLs izei height, GLenum format, GLenum type, DOMArrayBufferView* pixels)
453 { 498 {
454 if (isContextLost()) 499 if (isContextLost())
455 return; 500 return;
456 if (m_boundPixelPackBuffer.get()) { 501 if (m_boundPixelPackBuffer.get()) {
457 synthesizeGLError(GL_INVALID_OPERATION, "readPixels", "PIXEL_PACK buffer should not be bound"); 502 synthesizeGLError(GL_INVALID_OPERATION, "readPixels", "PIXEL_PACK buffer should not be bound");
458 return; 503 return;
459 } 504 }
460 505
461 WebGLRenderingContextBase::readPixels(x, y, width, height, format, type, pix els); 506 WebGLRenderingContextBase::readPixels(x, y, width, height, format, type, pix els);
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
598 if (!validateSize("renderbufferStorage", width, height)) 643 if (!validateSize("renderbufferStorage", width, height))
599 return; 644 return;
600 if (samples < 0) { 645 if (samples < 0) {
601 synthesizeGLError(GL_INVALID_VALUE, functionName, "samples < 0"); 646 synthesizeGLError(GL_INVALID_VALUE, functionName, "samples < 0");
602 return; 647 return;
603 } 648 }
604 renderbufferStorageImpl(target, samples, internalformat, width, height, func tionName); 649 renderbufferStorageImpl(target, samples, internalformat, width, height, func tionName);
605 applyStencilTest(); 650 applyStencilTest();
606 } 651 }
607 652
653 void WebGL2RenderingContextBase::resetUnpackParameters()
654 {
655 if (m_unpackAlignment != 1)
656 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
657 if (!m_unpackRowLength)
658 webContext()->pixelStorei(GL_UNPACK_ROW_LENGTH, 0);
659 if (!m_unpackImageHeight)
660 webContext()->pixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
661 if (!m_unpackSkipPixels)
662 webContext()->pixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
663 if (!m_unpackSkipRows)
664 webContext()->pixelStorei(GL_UNPACK_SKIP_ROWS, 0);
665 if (!m_unpackSkipImages)
666 webContext()->pixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
667 }
668
669 void WebGL2RenderingContextBase::restoreUnpackParameters()
670 {
671 if (m_unpackAlignment != 1)
672 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
673 if (!m_unpackRowLength)
674 webContext()->pixelStorei(GL_UNPACK_ROW_LENGTH, m_unpackRowLength);
675 if (!m_unpackImageHeight)
676 webContext()->pixelStorei(GL_UNPACK_IMAGE_HEIGHT, m_unpackImageHeight);
677 if (!m_unpackSkipPixels)
678 webContext()->pixelStorei(GL_UNPACK_SKIP_PIXELS, m_unpackSkipPixels);
679 if (!m_unpackSkipRows)
680 webContext()->pixelStorei(GL_UNPACK_SKIP_ROWS, m_unpackSkipRows);
681 if (!m_unpackSkipImages)
682 webContext()->pixelStorei(GL_UNPACK_SKIP_IMAGES, m_unpackSkipImages);
683 }
684
608 /* Texture objects */ 685 /* Texture objects */
609 bool WebGL2RenderingContextBase::validateTexStorage(const char* functionName, GL enum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei heigh t, GLsizei depth, TexStorageType functionType) 686 bool WebGL2RenderingContextBase::validateTexStorage(const char* functionName, GL enum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei heigh t, GLsizei depth, TexStorageType functionType)
610 { 687 {
611 if (functionType == TexStorageType2D) { 688 if (functionType == TexStorageType2D) {
612 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) { 689 if (target != GL_TEXTURE_2D && target != GL_TEXTURE_CUBE_MAP) {
613 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid 2D target" ); 690 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid 2D target" );
614 return false; 691 return false;
615 } 692 }
616 } else { 693 } else {
617 if (target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_ARRAY) { 694 if (target != GL_TEXTURE_3D && target != GL_TEXTURE_2D_ARRAY) {
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
793 bool needConversion = true; 870 bool needConversion = true;
794 if (type == GL_UNSIGNED_BYTE && sourceDataFormat == WebGLImageConversion::Da taFormatRGBA8 && format == GL_RGBA && alphaOp == WebGLImageConversion::AlphaDoNo thing && !flipY) { 871 if (type == GL_UNSIGNED_BYTE && sourceDataFormat == WebGLImageConversion::Da taFormatRGBA8 && format == GL_RGBA && alphaOp == WebGLImageConversion::AlphaDoNo thing && !flipY) {
795 needConversion = false; 872 needConversion = false;
796 } else { 873 } else {
797 if (!WebGLImageConversion::packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtrac tor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) { 874 if (!WebGLImageConversion::packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtrac tor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
798 synthesizeGLError(GL_INVALID_VALUE, "texSubImage3D", "bad image data "); 875 synthesizeGLError(GL_INVALID_VALUE, "texSubImage3D", "bad image data ");
799 return; 876 return;
800 } 877 }
801 } 878 }
802 879
803 if (m_unpackAlignment != 1) 880 resetUnpackParameters();
bajones 2015/11/25 00:03:05 There are several similar bits of code in WebGLRen
Ken Russell (switch to Gerrit) 2015/11/25 00:59:41 Agree with this. It looks like WebGLRenderingConte
Zhenyao Mo 2015/11/25 18:18:48 Done.
804 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
805 webContext()->texSubImage3D(target, level, xoffset, yoffset, zoffset, imageE xtractor.imageWidth(), imageExtractor.imageHeight(), 1, format, type, needConver sion ? data.data() : imagePixelData); 881 webContext()->texSubImage3D(target, level, xoffset, yoffset, zoffset, imageE xtractor.imageWidth(), imageExtractor.imageHeight(), 1, format, type, needConver sion ? data.data() : imagePixelData);
806 if (m_unpackAlignment != 1) 882 restoreUnpackParameters();
807 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
808 } 883 }
809 884
810 void WebGL2RenderingContextBase::texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei d epth, GLenum format, GLenum type, DOMArrayBufferView* pixels) 885 void WebGL2RenderingContextBase::texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei d epth, GLenum format, GLenum type, DOMArrayBufferView* pixels)
811 { 886 {
812 if (isContextLost() || !pixels || !validateTexSubImage3D("texSubImage3D", ta rget, level, xoffset, yoffset, zoffset, format, type, width, height, depth) 887 if (isContextLost() || !pixels || !validateTexSubImage3D("texSubImage3D", ta rget, level, xoffset, yoffset, zoffset, format, type, width, height, depth)
813 || !validateTexFuncData("texSubImage3D", level, width, height, format, t ype, pixels, NullAllowed)) 888 || !validateTexFuncData("texSubImage3D", level, width, height, format, t ype, pixels, NullAllowed))
814 return; 889 return;
815 890
816 // FIXME: Ensure pixels is large enough to contain the desired texture dimen sions. 891 // FIXME: Ensure pixels is large enough to contain the desired texture dimen sions.
817 892
818 void* data = pixels->baseAddress(); 893 void* data = pixels->baseAddress();
819 Vector<uint8_t> tempData; 894 Vector<uint8_t> tempData;
820 bool changeUnpackAlignment = false; 895 bool changeUnpackParameters = false;
821 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) { 896 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
822 if (!WebGLImageConversion::extractTextureData(width, height, format, typ e, 897 // FIXME: WebGLImageConversion needs to be updated to accept image depth .
823 m_unpackAlignment, 898 notImplemented();
824 m_unpackFlipY, m_unpackPremultiplyAlpha, 899 changeUnpackParameters = true;
825 data,
826 tempData))
827 return;
828 data = tempData.data();
829 changeUnpackAlignment = true;
830 } 900 }
831 if (changeUnpackAlignment) 901 if (changeUnpackParameters)
832 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1); 902 resetUnpackParameters();
833 webContext()->texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data); 903 webContext()->texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data);
834 if (changeUnpackAlignment) 904 if (changeUnpackParameters)
835 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment); 905 restoreUnpackParameters();
836 } 906 }
837 907
838 void WebGL2RenderingContextBase::texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLenum format, GLenum type, ImageData* p ixels) 908 void WebGL2RenderingContextBase::texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLenum format, GLenum type, ImageData* p ixels)
839 { 909 {
840 if (isContextLost() || !pixels || !validateTexSubImage3D("texSubImage3D", ta rget, level, xoffset, yoffset, zoffset, format, type, pixels->width(), pixels->h eight(), 1)) 910 if (isContextLost() || !pixels || !validateTexSubImage3D("texSubImage3D", ta rget, level, xoffset, yoffset, zoffset, format, type, pixels->width(), pixels->h eight(), 1))
841 return; 911 return;
842 912
843 if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) { 913 if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
844 // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented. 914 // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
845 type = GL_FLOAT; 915 type = GL_FLOAT;
846 } 916 }
847 Vector<uint8_t> data; 917 Vector<uint8_t> data;
848 bool needConversion = true; 918 bool needConversion = true;
849 // The data from ImageData is always of format RGBA8. 919 // The data from ImageData is always of format RGBA8.
850 // No conversion is needed if destination format is RGBA and type is USIGNED _BYTE and no Flip or Premultiply operation is required. 920 // No conversion is needed if destination format is RGBA and type is USIGNED _BYTE and no Flip or Premultiply operation is required.
851 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE && !m_unpackFlipY && !m_un packPremultiplyAlpha) { 921 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE && !m_unpackFlipY && !m_un packPremultiplyAlpha) {
852 needConversion = false; 922 needConversion = false;
853 } else { 923 } else {
854 if (!WebGLImageConversion::extractImageData(pixels->data()->data(), pixe ls->size(), format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) { 924 if (!WebGLImageConversion::extractImageData(pixels->data()->data(), pixe ls->size(), format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
855 synthesizeGLError(GL_INVALID_VALUE, "texSubImage3D", "bad image data "); 925 synthesizeGLError(GL_INVALID_VALUE, "texSubImage3D", "bad image data ");
856 return; 926 return;
857 } 927 }
858 } 928 }
859 if (m_unpackAlignment != 1) 929 resetUnpackParameters();
860 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
861 webContext()->texSubImage3D(target, level, xoffset, yoffset, zoffset, pixels ->width(), pixels->height(), 1, format, type, needConversion ? data.data() : pix els->data()->data()); 930 webContext()->texSubImage3D(target, level, xoffset, yoffset, zoffset, pixels ->width(), pixels->height(), 1, format, type, needConversion ? data.data() : pix els->data()->data());
862 if (m_unpackAlignment != 1) 931 restoreUnpackParameters();
863 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
864 } 932 }
865 933
866 void WebGL2RenderingContextBase::texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLenum format, GLenum type, HTMLImageEle ment* image, ExceptionState& exceptionState) 934 void WebGL2RenderingContextBase::texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLenum format, GLenum type, HTMLImageEle ment* image, ExceptionState& exceptionState)
867 { 935 {
868 if (isContextLost() || !image || !validateHTMLImageElement("texSubImage3D", image, exceptionState)) 936 if (isContextLost() || !image || !validateHTMLImageElement("texSubImage3D", image, exceptionState))
869 return; 937 return;
870 938
871 RefPtr<Image> imageForRender = image->cachedImage()->image(); 939 RefPtr<Image> imageForRender = image->cachedImage()->image();
872 if (imageForRender->isSVGImage()) 940 if (imageForRender->isSVGImage())
873 imageForRender = drawImageIntoBuffer(imageForRender.get(), image->width( ), image->height(), "texSubImage3D"); 941 imageForRender = drawImageIntoBuffer(imageForRender.get(), image->width( ), image->height(), "texSubImage3D");
(...skipping 1574 matching lines...) Expand 10 before | Expand all | Expand 10 after
2448 return getBooleanParameter(scriptState, pname); 2516 return getBooleanParameter(scriptState, pname);
2449 case GL_UNIFORM_BUFFER_BINDING: 2517 case GL_UNIFORM_BUFFER_BINDING:
2450 return WebGLAny(scriptState, m_boundUniformBuffer.get()); 2518 return WebGLAny(scriptState, m_boundUniformBuffer.get());
2451 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: 2519 case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
2452 return getIntParameter(scriptState, pname); 2520 return getIntParameter(scriptState, pname);
2453 case GL_UNPACK_IMAGE_HEIGHT: 2521 case GL_UNPACK_IMAGE_HEIGHT:
2454 return getIntParameter(scriptState, pname); 2522 return getIntParameter(scriptState, pname);
2455 case GL_UNPACK_ROW_LENGTH: 2523 case GL_UNPACK_ROW_LENGTH:
2456 return getIntParameter(scriptState, pname); 2524 return getIntParameter(scriptState, pname);
2457 case GL_UNPACK_SKIP_IMAGES: 2525 case GL_UNPACK_SKIP_IMAGES:
2458 return getBooleanParameter(scriptState, pname); 2526 return getIntParameter(scriptState, pname);
2459 case GL_UNPACK_SKIP_PIXELS: 2527 case GL_UNPACK_SKIP_PIXELS:
2460 return getBooleanParameter(scriptState, pname); 2528 return getIntParameter(scriptState, pname);
2461 case GL_UNPACK_SKIP_ROWS: 2529 case GL_UNPACK_SKIP_ROWS:
2462 return getBooleanParameter(scriptState, pname); 2530 return getIntParameter(scriptState, pname);
2463 2531
2464 default: 2532 default:
2465 return WebGLRenderingContextBase::getParameter(scriptState, pname); 2533 return WebGLRenderingContextBase::getParameter(scriptState, pname);
2466 } 2534 }
2467 } 2535 }
2468 2536
2469 ScriptValue WebGL2RenderingContextBase::getInt64Parameter(ScriptState* scriptSta te, GLenum pname) 2537 ScriptValue WebGL2RenderingContextBase::getInt64Parameter(ScriptState* scriptSta te, GLenum pname)
2470 { 2538 {
2471 GLint64 value = 0; 2539 GLint64 value = 0;
2472 if (!isContextLost()) 2540 if (!isContextLost())
(...skipping 652 matching lines...) Expand 10 before | Expand all | Expand 10 after
3125 GLenum WebGL2RenderingContextBase::boundFramebufferColorFormat() 3193 GLenum WebGL2RenderingContextBase::boundFramebufferColorFormat()
3126 { 3194 {
3127 if (m_readFramebufferBinding && m_readFramebufferBinding->object()) 3195 if (m_readFramebufferBinding && m_readFramebufferBinding->object())
3128 return m_readFramebufferBinding->colorBufferFormat(); 3196 return m_readFramebufferBinding->colorBufferFormat();
3129 if (m_requestedAttributes.alpha()) 3197 if (m_requestedAttributes.alpha())
3130 return GL_RGBA; 3198 return GL_RGBA;
3131 return GL_RGB; 3199 return GL_RGB;
3132 } 3200 }
3133 3201
3134 } // namespace blink 3202 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698