17a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita/*
27a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita * Copyright 2015 Google Inc.
37a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita *
47a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita * Use of this source code is governed by a BSD-style license that can be
57a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita * found in the LICENSE file.
67a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita */
77a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
8ff2742eba814c906686b72abd2d1b3e6b720d784Hal Canary#include "SkTypes.h"
9ff2742eba814c906686b72abd2d1b3e6b720d784Hal Canary
10ff2742eba814c906686b72abd2d1b3e6b720d784Hal Canary#ifdef SK_XML
11ff2742eba814c906686b72abd2d1b3e6b720d784Hal Canary
127a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "SkCanvas.h"
137a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "SkData.h"
147a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "SkDOM.h"
157a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "SkParse.h"
167a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "SkStream.h"
177a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "SkSVGCanvas.h"
187a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "SkXMLWriter.h"
197a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include "Test.h"
207a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
217a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita#include <string.h>
227a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
237a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalitanamespace {
247a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
257a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalitavoid check_text_node(skiatest::Reporter* reporter,
267a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita                     const SkDOM& dom,
277a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita                     const SkDOM::Node* root,
287a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita                     const SkPoint& offset,
297a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita                     unsigned scalarsPerPos,
307a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita                     const char* expected) {
3196fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (root == nullptr) {
327a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        ERRORF(reporter, "root element not found.");
337a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        return;
347a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
357a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
367a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    const SkDOM::Node* textElem = dom.getFirstChild(root, "text");
3796fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (textElem == nullptr) {
387a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        ERRORF(reporter, "<text> element not found.");
397a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        return;
407a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
417a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    REPORTER_ASSERT(reporter, dom.getType(textElem) == SkDOM::kElement_Type);
427a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
437a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    const SkDOM::Node* textNode= dom.getFirstChild(textElem);
4496fcdcc219d2a0d3579719b84b28bede76efba64halcanary    REPORTER_ASSERT(reporter, textNode != nullptr);
4596fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (textNode != nullptr) {
467a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        REPORTER_ASSERT(reporter, dom.getType(textNode) == SkDOM::kText_Type);
477a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        REPORTER_ASSERT(reporter, strcmp(expected, dom.getName(textNode)) == 0);
487a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
497a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
507a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    int textLen = SkToInt(strlen(expected));
517a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
527a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    const char* x = dom.findAttr(textElem, "x");
5396fcdcc219d2a0d3579719b84b28bede76efba64halcanary    REPORTER_ASSERT(reporter, x != nullptr);
5496fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (x != nullptr) {
557a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        int xposCount = (scalarsPerPos < 1) ? 1 : textLen;
567a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        REPORTER_ASSERT(reporter, SkParse::Count(x) == xposCount);
577a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
587a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkAutoTMalloc<SkScalar> xpos(xposCount);
597a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkParse::FindScalars(x, xpos.get(), xposCount);
607a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        if (scalarsPerPos < 1) {
617a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita            REPORTER_ASSERT(reporter, xpos[0] == offset.x());
627a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        } else {
637a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita            for (int i = 0; i < xposCount; ++i) {
647a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita                REPORTER_ASSERT(reporter, xpos[i] == SkIntToScalar(expected[i]));
657a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita            }
667a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        }
677a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
687a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
697a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    const char* y = dom.findAttr(textElem, "y");
7096fcdcc219d2a0d3579719b84b28bede76efba64halcanary    REPORTER_ASSERT(reporter, y != nullptr);
7196fcdcc219d2a0d3579719b84b28bede76efba64halcanary    if (y != nullptr) {
727a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        int yposCount = (scalarsPerPos < 2) ? 1 : textLen;
737a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        REPORTER_ASSERT(reporter, SkParse::Count(y) == yposCount);
747a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
757a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkAutoTMalloc<SkScalar> ypos(yposCount);
767a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkParse::FindScalars(y, ypos.get(), yposCount);
777a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        if (scalarsPerPos < 2) {
787a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita            REPORTER_ASSERT(reporter, ypos[0] == offset.y());
797a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        } else {
807a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita            for (int i = 0; i < yposCount; ++i) {
817a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita                REPORTER_ASSERT(reporter, ypos[i] == -SkIntToScalar(expected[i]));
827a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita            }
837a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        }
847a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
857a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita}
867a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
877a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalitavoid test_whitespace_pos(skiatest::Reporter* reporter,
887a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita                         const char* txt,
897a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita                         const char* expected) {
907a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    size_t len = strlen(txt);
917a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
927a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    SkDOM dom;
937a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    SkPaint paint;
947a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    SkPoint offset = SkPoint::Make(10, 20);
957a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
967a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    {
977a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkXMLParserWriter writer(dom.beginParsing());
985df4934b3e40cdc378e225d1dda39f015cae9baeMike Reed        std::unique_ptr<SkCanvas> svgCanvas = SkSVGCanvas::Make(SkRect::MakeWH(100, 100), &writer);
997a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        svgCanvas->drawText(txt, len, offset.x(), offset.y(), paint);
1007a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
1017a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    check_text_node(reporter, dom, dom.finishParsing(), offset, 0, expected);
1027a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
1037a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    {
1047a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkAutoTMalloc<SkScalar> xpos(len);
1057a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        for (int i = 0; i < SkToInt(len); ++i) {
1067a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita            xpos[i] = SkIntToScalar(txt[i]);
1077a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        }
1087a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
1097a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkXMLParserWriter writer(dom.beginParsing());
1105df4934b3e40cdc378e225d1dda39f015cae9baeMike Reed        std::unique_ptr<SkCanvas> svgCanvas = SkSVGCanvas::Make(SkRect::MakeWH(100, 100), &writer);
1117a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        svgCanvas->drawPosTextH(txt, len, xpos, offset.y(), paint);
1127a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
1137a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    check_text_node(reporter, dom, dom.finishParsing(), offset, 1, expected);
1147a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
1157a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    {
1167a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkAutoTMalloc<SkPoint> pos(len);
1177a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        for (int i = 0; i < SkToInt(len); ++i) {
1187a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita            pos[i] = SkPoint::Make(SkIntToScalar(txt[i]), -SkIntToScalar(txt[i]));
1197a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        }
1207a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
1217a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        SkXMLParserWriter writer(dom.beginParsing());
1225df4934b3e40cdc378e225d1dda39f015cae9baeMike Reed        std::unique_ptr<SkCanvas> svgCanvas = SkSVGCanvas::Make(SkRect::MakeWH(100, 100), &writer);
1237a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        svgCanvas->drawPosText(txt, len, pos, paint);
1247a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
1257a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    check_text_node(reporter, dom, dom.finishParsing(), offset, 2, expected);
1267a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita}
1277a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
1287a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita}
1297a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
1307a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalitaDEF_TEST(SVGDevice_whitespace_pos, reporter) {
1317a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    static const struct {
1327a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        const char* tst_in;
1337a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        const char* tst_out;
1347a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    } tests[] = {
1357a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        { "abcd"      , "abcd" },
1367a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        { "ab cd"     , "ab cd" },
1377a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        { "ab \t\t cd", "ab cd" },
1387a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        { " abcd"     , "abcd" },
1397a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        { "  abcd"    , "abcd" },
1407a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        { " \t\t abcd", "abcd" },
1417a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        { "abcd "     , "abcd " }, // we allow one trailing whitespace char
1427a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        { "abcd  "    , "abcd " }, // because it makes no difference and
1437a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        { "abcd\t  "  , "abcd\t" }, // simplifies the implementation
1447a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        { "\t\t  \t ab \t\t  \t cd \t\t   \t  ", "ab cd " },
1457a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    };
1467a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita
1477a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    for (unsigned i = 0; i < SK_ARRAY_COUNT(tests); ++i) {
1487a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita        test_whitespace_pos(reporter, tests[i].tst_in, tests[i].tst_out);
1497a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita    }
1507a048690d3cb6b3c1bdef594c3bd4b66f6b400c1fmalita}
151ff2742eba814c906686b72abd2d1b3e6b720d784Hal Canary
152ff2742eba814c906686b72abd2d1b3e6b720d784Hal Canary#endif
153