| //********************************************************************************* |
| // Rendition.cc |
| //--------------------------------------------------------------------------------- |
| // |
| //--------------------------------------------------------------------------------- |
| // Hugo Mercier <hmercier31[at]gmail.com> (c) 2008 |
| // Pino Toscano <pino@kde.org> (c) 2008 |
| // Carlos Garcia Campos <carlosgc@gnome.org> (c) 2010 |
| // Tobias Koenig <tobias.koenig@kdab.com> (c) 2012 |
| // Albert Astals Cid <aacid@kde.org> (C) 2017, 2018, 2024 |
| // |
| // This program is free software; you can redistribute it and/or modify |
| // it under the terms of the GNU General Public License as published by |
| // the Free Software Foundation; either version 2 of the License, or |
| // (at your option) any later version. |
| // |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public License |
| // along with this program; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| //********************************************************************************* |
| |
| #include <cmath> |
| #include "Rendition.h" |
| #include "FileSpec.h" |
| |
| MediaWindowParameters::MediaWindowParameters() |
| { |
| // default values |
| type = windowEmbedded; |
| width = -1; |
| height = -1; |
| relativeTo = windowRelativeToDocument; |
| XPosition = 0.5; |
| YPosition = 0.5; |
| hasTitleBar = true; |
| hasCloseButton = true; |
| isResizeable = true; |
| } |
| |
| MediaWindowParameters::~MediaWindowParameters() { } |
| |
| void MediaWindowParameters::parseFWParams(Object *obj) |
| { |
| Object tmp = obj->dictLookup("D"); |
| if (tmp.isArray()) { |
| Array *dim = tmp.getArray(); |
| |
| if (dim->getLength() >= 2) { |
| Object dd = dim->get(0); |
| if (dd.isInt()) { |
| width = dd.getInt(); |
| } |
| |
| dd = dim->get(1); |
| if (dd.isInt()) { |
| height = dd.getInt(); |
| } |
| } |
| } |
| |
| tmp = obj->dictLookup("RT"); |
| if (tmp.isInt()) { |
| int t = tmp.getInt(); |
| switch (t) { |
| case 0: |
| relativeTo = windowRelativeToDocument; |
| break; |
| case 1: |
| relativeTo = windowRelativeToApplication; |
| break; |
| case 2: |
| relativeTo = windowRelativeToDesktop; |
| break; |
| } |
| } |
| |
| tmp = obj->dictLookup("P"); |
| if (tmp.isInt()) { |
| int t = tmp.getInt(); |
| |
| switch (t) { |
| case 0: // Upper left |
| XPosition = 0.0; |
| YPosition = 0.0; |
| break; |
| case 1: // Upper Center |
| XPosition = 0.5; |
| YPosition = 0.0; |
| break; |
| case 2: // Upper Right |
| XPosition = 1.0; |
| YPosition = 0.0; |
| break; |
| case 3: // Center Left |
| XPosition = 0.0; |
| YPosition = 0.5; |
| break; |
| case 4: // Center |
| XPosition = 0.5; |
| YPosition = 0.5; |
| break; |
| case 5: // Center Right |
| XPosition = 1.0; |
| YPosition = 0.5; |
| break; |
| case 6: // Lower Left |
| XPosition = 0.0; |
| YPosition = 1.0; |
| break; |
| case 7: // Lower Center |
| XPosition = 0.5; |
| YPosition = 1.0; |
| break; |
| case 8: // Lower Right |
| XPosition = 1.0; |
| YPosition = 1.0; |
| break; |
| } |
| } |
| |
| tmp = obj->dictLookup("T"); |
| if (tmp.isBool()) { |
| hasTitleBar = tmp.getBool(); |
| } |
| tmp = obj->dictLookup("UC"); |
| if (tmp.isBool()) { |
| hasCloseButton = tmp.getBool(); |
| } |
| tmp = obj->dictLookup("R"); |
| if (tmp.isInt()) { |
| isResizeable = (tmp.getInt() != 0); |
| } |
| } |
| |
| MediaParameters::MediaParameters() |
| { |
| // instanciate to default values |
| |
| volume = 100; |
| fittingPolicy = fittingUndefined; |
| autoPlay = true; |
| repeatCount = 1.0; |
| opacity = 1.0; |
| showControls = false; |
| duration = 0; |
| } |
| |
| MediaParameters::~MediaParameters() { } |
| |
| void MediaParameters::parseMediaPlayParameters(Object *obj) |
| { |
| Object tmp = obj->dictLookup("V"); |
| if (tmp.isInt()) { |
| volume = tmp.getInt(); |
| } |
| |
| tmp = obj->dictLookup("C"); |
| if (tmp.isBool()) { |
| showControls = tmp.getBool(); |
| } |
| |
| tmp = obj->dictLookup("F"); |
| if (tmp.isInt()) { |
| int t = tmp.getInt(); |
| |
| switch (t) { |
| case 0: |
| fittingPolicy = fittingMeet; |
| break; |
| case 1: |
| fittingPolicy = fittingSlice; |
| break; |
| case 2: |
| fittingPolicy = fittingFill; |
| break; |
| case 3: |
| fittingPolicy = fittingScroll; |
| break; |
| case 4: |
| fittingPolicy = fittingHidden; |
| break; |
| case 5: |
| fittingPolicy = fittingUndefined; |
| break; |
| } |
| } |
| |
| // duration parsing |
| // duration's default value is set to 0, which means : intrinsinc media duration |
| tmp = obj->dictLookup("D"); |
| if (tmp.isDict()) { |
| Object oname = tmp.dictLookup("S"); |
| if (oname.isName()) { |
| const char *name = oname.getName(); |
| if (!strcmp(name, "F")) { |
| duration = -1; // infinity |
| } else if (!strcmp(name, "T")) { |
| Object ddict = tmp.dictLookup("T"); |
| if (ddict.isDict()) { |
| Object tmp2 = ddict.dictLookup("V"); |
| if (tmp2.isNum()) { |
| duration = (unsigned long)(tmp2.getNum()); |
| } |
| } |
| } |
| } |
| } |
| |
| tmp = obj->dictLookup("A"); |
| if (tmp.isBool()) { |
| autoPlay = tmp.getBool(); |
| } |
| |
| tmp = obj->dictLookup("RC"); |
| if (tmp.isNum()) { |
| repeatCount = tmp.getNum(); |
| } |
| } |
| |
| void MediaParameters::parseMediaScreenParameters(Object *obj) |
| { |
| Object tmp = obj->dictLookup("W"); |
| if (tmp.isInt()) { |
| int t = tmp.getInt(); |
| |
| switch (t) { |
| case 0: |
| windowParams.type = MediaWindowParameters::windowFloating; |
| break; |
| case 1: |
| windowParams.type = MediaWindowParameters::windowFullscreen; |
| break; |
| case 2: |
| windowParams.type = MediaWindowParameters::windowHidden; |
| break; |
| case 3: |
| windowParams.type = MediaWindowParameters::windowEmbedded; |
| break; |
| } |
| } |
| |
| // background color |
| tmp = obj->dictLookup("B"); |
| if (tmp.isArray()) { |
| Array *color = tmp.getArray(); |
| |
| Object component = color->get(0); |
| bgColor.r = component.getNum(); |
| |
| component = color->get(1); |
| bgColor.g = component.getNum(); |
| |
| component = color->get(2); |
| bgColor.b = component.getNum(); |
| } |
| |
| // opacity |
| tmp = obj->dictLookup("O"); |
| if (tmp.isNum()) { |
| opacity = tmp.getNum(); |
| } |
| |
| if (windowParams.type == MediaWindowParameters::windowFloating) { |
| Object winDict = obj->dictLookup("F"); |
| if (winDict.isDict()) { |
| windowParams.parseFWParams(&winDict); |
| } |
| } |
| } |
| |
| MediaRendition::~MediaRendition() = default; |
| |
| MediaRendition::MediaRendition(Object *obj) |
| { |
| bool hasClip = false; |
| |
| ok = true; |
| isEmbedded = false; |
| |
| // |
| // Parse media clip data |
| // |
| Object tmp2 = obj->dictLookup("C"); |
| if (tmp2.isDict()) { // media clip |
| hasClip = true; |
| Object tmp = tmp2.dictLookup("S"); |
| if (tmp.isName()) { |
| if (!strcmp(tmp.getName(), "MCD")) { // media clip data |
| Object obj1 = tmp2.dictLookup("D"); |
| if (obj1.isDict()) { |
| Object obj2 = obj1.dictLookup("F"); |
| if (obj2.isString()) { |
| fileName = obj2.getString()->copy(); |
| } |
| obj2 = obj1.dictLookup("EF"); |
| if (obj2.isDict()) { |
| Object embedded = obj2.dictLookup("F"); |
| if (embedded.isStream()) { |
| isEmbedded = true; |
| embeddedStreamObject = embedded.copy(); |
| } |
| } |
| |
| // TODO: D might be a form XObject too |
| } else { |
| error(errSyntaxError, -1, "Invalid Media Clip Data"); |
| ok = false; |
| } |
| |
| // FIXME: ignore CT if D is a form XObject |
| obj1 = tmp2.dictLookup("CT"); |
| if (obj1.isString()) { |
| contentType = obj1.getString()->copy(); |
| } |
| } else if (!strcmp(tmp.getName(), "MCS")) { // media clip data |
| // TODO |
| } |
| } else { |
| error(errSyntaxError, -1, "Invalid Media Clip"); |
| ok = false; |
| } |
| } |
| |
| if (!ok) { |
| return; |
| } |
| |
| // |
| // parse Media Play Parameters |
| tmp2 = obj->dictLookup("P"); |
| if (tmp2.isDict()) { // media play parameters |
| Object params = tmp2.dictLookup("MH"); |
| if (params.isDict()) { |
| MH.parseMediaPlayParameters(¶ms); |
| } |
| params = tmp2.dictLookup("BE"); |
| if (params.isDict()) { |
| BE.parseMediaPlayParameters(¶ms); |
| } |
| } else if (!hasClip) { |
| error(errSyntaxError, -1, "Invalid Media Rendition"); |
| ok = false; |
| } |
| |
| // |
| // parse Media Screen Parameters |
| tmp2 = obj->dictLookup("SP"); |
| if (tmp2.isDict()) { // media screen parameters |
| Object params = tmp2.dictLookup("MH"); |
| if (params.isDict()) { |
| MH.parseMediaScreenParameters(¶ms); |
| } |
| params = tmp2.dictLookup("BE"); |
| if (params.isDict()) { |
| BE.parseMediaScreenParameters(¶ms); |
| } |
| } |
| } |
| |
| MediaRendition::MediaRendition(const MediaRendition &other) |
| { |
| ok = other.ok; |
| MH = other.MH; |
| BE = other.BE; |
| isEmbedded = other.isEmbedded; |
| embeddedStreamObject = other.embeddedStreamObject.copy(); |
| |
| if (other.contentType) { |
| contentType = other.contentType->copy(); |
| } |
| |
| if (other.fileName) { |
| fileName = other.fileName->copy(); |
| } |
| } |
| |
| void MediaRendition::outputToFile(FILE *fp) |
| { |
| if (!isEmbedded) { |
| return; |
| } |
| |
| embeddedStreamObject.streamReset(); |
| |
| while (true) { |
| int c = embeddedStreamObject.streamGetChar(); |
| if (c == EOF) { |
| break; |
| } |
| |
| fwrite(&c, 1, 1, fp); |
| } |
| } |
| |
| std::unique_ptr<MediaRendition> MediaRendition::copy() const |
| { |
| return std::make_unique<MediaRendition>(*this); |
| } |
| |
| // TODO: SelectorRendition |